iOS 常见面试题 -- Runtime

Runtime,运行时,
OC是一门动态性较强的语言,它允许很多操作延迟到运行时执行
OC的动态性就是由runtime来支撑和实现的,利用runtime可以做很多事情
比如
1、利用关联函数给分类添加属性
2、遍历类的成员变量以及方法
3、交换系统方法
4、利用消息转发机制解决方法找不到的问题

OC中方法的调用 其实都是转化为 objc_msgSend函数的调用

objc_msgSend函数的执行流程可以分为3大阶段

一、消息发送阶段

首先判断消息接收者是否为nil 如果为空直接退出
1、去自己类的方法缓存列表中查找该方法如果找到则执行该方法,
2、否则去自己类的方法列表中查找该方法 如果找到先缓存该方法然后再执行,
3、否则去自己父类的方法缓存列表中查找该方法  如果找到先缓存该方法到
自己类中,然后执行该方法,
4、否则去自己父类的方法列表中查找该方法如果找到先缓存该方法到自己类中,
然后执行该方法,否则 到第二阶段 

第一阶段流程图如下所示


消息发送阶段流程图.png

二、动态方法解析阶段

1、首先判断曾经有过动态解析  如果没有则调用 +resolveInstanceMethod:
或则+resoveClassMethod:方法来动态解析然后标记为已经动态解析
最后重新走“消息发送”的流程

2、如果曾经有过动态解析 则直接消息发送流程

如果第二阶段不做任何处理 则直接进入第三阶段

第二阶段流程图如下所示:


动态解析阶段流程图.png

三、消息转发阶段

顾名思义就是 自己没有能力处理这个方法 他需要将此方法转交给别人类处理。

1、首先调用 forwardingTargetForSelector:方法 
在此方法中可以返回一个可以处理消息的对象,
如果对象存在则直接给对象转发消息,
如果对象不存在否则进入第2步 调用方法签名函数

2、调用methodSignatureForSelector:方法(方法签名函数)在此方法中:
如果返回值为空 则直接调用 调用doesNotRecognizeSelector:方法 
然后程序报错:unrecognized selector sent to instance 经典错误
如果返回值不为空 则直接进入第3步 调用 forwardInvocation方法

3、forwardInvocation:方法
开发人员可以在此方法中返回一个对象来转发此消息

第三阶段流程图如下所示


消息转发阶段流程图.png

举例:
1、首先我们创建一个类(Person 类) 然后在 Person 类中声明一个对象方法(test)且不去实现

Person.h 声明一个test方法

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject

- (void)test;

@end

NS_ASSUME_NONNULL_END

2、在其他地方调用 Person 类对象方法(test)

ViewController.m 调用 Person 类对象方法(test)

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor redColor];
    Person *person = [[Person alloc]init];
    [person test];
}

如果我们不做任何处理 则程序就会奔溃 报如下错误:

2021-01-19 10:18:44.480279+0800 LLLL[40671:839012] -[Person test]: unrecognized selector sent to instance 0x600000e20000
2021-01-19 10:18:44.485940+0800 LLLL[40671:839012] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person test]: unrecognized selector sent to instance 0x600000e20000'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff23e3de6e __exceptionPreprocess + 350
    1   libobjc.A.dylib                     0x00007fff512a19b2 objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff23e5eb94 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
    3   CoreFoundation                      0x00007fff23e4286c ___forwarding___ + 1436
    4   CoreFoundation                      0x00007fff23e44b58 _CF_forwarding_prep_0 + 120
    5   LLLL                                0x0000000102a9ff2e -[ViewController viewDidLoad] + 206
    6   UIKitCore                           0x00007fff48cc294e -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 83
    7   UIKitCore                           0x00007fff48cc786c -[UIViewController loadViewIfRequired] + 1084
    8   UIKitCore                           0x00007fff48cc7c89 -[UIViewController view] + 27
    9   UIKitCore                           0x00007fff493ab2d5 -[UIWindow addRootViewControllerViewIfPossible] + 326
    10  UIKitCore                           0x00007fff493aa8fe -[UIWindow _updateLayerOrderingAndSetLayerHidden:actionBlock:] + 219
    11  UIKitCore                           0x00007fff493ab989 -[UIWindow _setHidden:forced:] + 362
    12  UIKit                               0x0000000102fa4dc4 -[UIWindowAccessibility _orderFrontWithoutMakingKey] + 84
    13  UIKitCore                           0x00007fff493bedc5 -[UIWindow _mainQueue_makeKeyAndVisible] + 42
    14  UIKitCore                           0x00007fff495e0cdb -[UIWindowScene _makeKeyAndVisibleIfNeeded] + 202
    15  UIKitCore                           0x00007fff488cec30 +[UIScene _sceneForFBSScene:create:withSession:connectionOptions:] + 1405
    16  UIKitCore                           0x00007fff4936eca5 -[UIApplication _connectUISceneFromFBSScene:transitionContext:] + 1019
    17  UIKitCore                           0x00007fff4936efdc -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 291
    18  UIKitCore                           0x00007fff48ec177c -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 361
    19  FrontBoardServices                  0x00007fff36d03d2e -[FBSSceneImpl _callOutQueue_agent_didCreateWithTransitionContext:completion:] + 419
    20  FrontBoardServices                  0x00007fff36d29dc1 __86-[FBSWorkspaceScenesClient sceneID:createWithParameters:transitionContext:completion:]_block_invoke.154 + 102
    21  FrontBoardServices                  0x00007fff36d0e757 -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 220
    22  FrontBoardServices                  0x00007fff36d29a52 __86-[FBSWorkspaceScenesClient sceneID:createWithParameters:transitionContext:completion:]_block_invoke + 355
    23  libdispatch.dylib                   0x0000000102d0ae8e _dispatch_client_callout + 8
    24  libdispatch.dylib                   0x0000000102d0dda2 _dispatch_block_invoke_direct + 300
    25  FrontBoardServices                  0x00007fff36d4f6e9 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 30
    26  FrontBoardServices                  0x00007fff36d4f3d7 -[FBSSerialQueue _queue_performNextIfPossible] + 441
    27  FrontBoardServices                  0x00007fff36d4f8e6 -[FBSSerialQueue _performNextFromRunLoopSource] + 22
    28  CoreFoundation                      0x00007fff23da1c91 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    29  CoreFoundation                      0x00007fff23da1bbc __CFRunLoopDoSource0 + 76
    30  CoreFoundation                      0x00007fff23da13ec __CFRunLoopDoSources0 + 268
    31  CoreFoundation                      0x00007fff23d9bf8e __CFRunLoopRun + 974
    32  CoreFoundation                      0x00007fff23d9b8a4 CFRunLoopRunSpecific + 404
    33  GraphicsServices                    0x00007fff38c05bbe GSEventRunModal + 139
    34  UIKitCore                           0x00007fff49372964 UIApplicationMain + 1605
    35  LLLL                                0x0000000102aa01d2 main + 114
    36  libdyld.dylib                       0x00007fff5211c1fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

接下来使用runtime运行时 来处理这个崩溃

第一阶段:消息发送阶段

此阶段为方法查找阶段  找到了则调用 
 找不到则 进行第二步 方法动态解析阶段 

第二阶段:动态方法解析阶段

在此阶段 我们可以添加一个新的方法来 otherTest 来代替 test

Person.m

#import "Person.h"
#import <objc/runtime.h>

@implementation Person


+ (BOOL)resolveInstanceMethod:(SEL)sel{

    if (sel == @selector(test)) {
        Method method = class_getInstanceMethod(self, @selector(otherTest));
        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
         return YES;
    }
    return [super resolveInstanceMethod:sel];
}

- (void)otherTest{
    NSLog(@"我是代替方法 ----  %s",__func__);
}
@end

运行程序结果打印如下:

2021-01-19 10:41:28.143085+0800 LLLL[41023:856445] 我是代替方法 ----  -[Person otherTest]

这是第一补救阶段,如果 +resolveInstanceMethod:函数内部不做任何处理或则直接不实现 则进入 第三阶段

第三阶段:消息转发阶段

准备:
首先再创建一个类(Student类) 然后在这个类中创建一个对象方法test 这个对象方法一定要与Person对象中的一样 这样才能找到 方法

Student.h

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Student : NSObject

- (void)test;

@end

NS_ASSUME_NONNULL_END

Student.m

#import "Student.h"

@implementation Student

- (void)test{
    
    NSLog(@"%s",__func__);

}
@end

实现:

进入第三阶段 首先会调用 forwardingTargetForSelector:方法 在此方法中我们可以把方法转发给别的类来处理

Person.m

#import "Person.h"
#import <objc/runtime.h>
#import "Student.h"
@implementation Person


//动态解析方法阶段
+ (BOOL)resolveInstanceMethod:(SEL)sel{

    
//    //注意⚠️ 如果不注释则无法进行第三阶段
    
//    if (sel == @selector(test)) {
//        Method method = class_getInstanceMethod(self, @selector(otherTest));
//        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
//         return YES;
//    }
    
    return [super resolveInstanceMethod:sel];
}

- (void)otherTest{
    NSLog(@"我是代替方法 ----  %s",__func__);
}


//消息转发阶段
- (id)forwardingTargetForSelector:(SEL)aSelector{
    if (aSelector == @selector(test)) {
        return  [[Student alloc]init];
    }
    return [super forwardingTargetForSelector:aSelector];
}

@end

此时运行代码 控制台打印如下:

2021-01-19 10:59:01.971909+0800 LLLL[41176:868929] -[Student test]

这一步则 完成了方法转发。

如果 forwardingTargetForSelector: 方法中未返回其他类 则会调用以下两个方法
methodSignatureForSelector:aSelector
forwardInvocation:anInvocation

Person.m

#import "Person.h"
#import <objc/runtime.h>
#import "Student.h"
@implementation Person


//动态解析方法阶段
+ (BOOL)resolveInstanceMethod:(SEL)sel{
    
    
    //    //注意⚠️ 如果不注释则无法进行第三阶段
    
    //    if (sel == @selector(test)) {
    //        Method method = class_getInstanceMethod(self, @selector(otherTest));
    //        class_addMethod(self, sel, method_getImplementation(method), method_getTypeEncoding(method));
    //         return YES;
    //    }
    
    return [super resolveInstanceMethod:sel];
}

- (void)otherTest{
    NSLog(@"我是代替方法 ----  %s",__func__);
}



//消息转发阶段
- (id)forwardingTargetForSelector:(SEL)aSelector{
    //    //如果此方法不注释 则不会走下一步
    //    if (aSelector == @selector(test)) {
    //        return  [[Student alloc]init];
    //    }
    return [super forwardingTargetForSelector:aSelector];
}

/*
 方法签名:返回值、返回类型
 
 
 */
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
    
    if (aSelector == @selector(test)) {
        /*
         v16@0:8
         
         第一个参数 返回值类型  如  v代表 void
         第二个参数  16 代表16个字这个节
         第三个参数  @ 代表一个对象
         第四个参数  0 从第0个字节开始
         第五个参数   : 代表SEL
         第六个参数  8代表从第八个字节开始
         
         可以简写成: v@:
         
         此处填写请参考:https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1
         
         举例1:
         - (BOOL)ifSuccess:(NSString *)tag
         
         其ObjCTypes为:"B@:@",其中:
         
         "B":代表BOOL。 // NSLog(@"%s",@encode(BOOL))的结果为B
         "@":一个id类型的对象,第一个参数类型,也就是objc _ msgSend的第一个参数
         ":":代表对应的SEL,第二个参数
         "@":一个id类型的对象,也就是tag。
         
         
         举例2;
         
         - (void)goToSchoolWithPerson:(Person *)person;
         [zhangsan goToSchoolWithPerson:lisi];
         
         其ObjCTypes为: "v@:@" 那究竟是如何得来该字符串呢?其实我们有两种方式:
         
         1、 直接查表。在Type Encodings里面列出了对应关系。 链接如上
         
         2、使用 @encode()计算。(如: NSLog(@"%s",@encode(BOOL))的结果为B )
         
         我们都知道消息发送会被转换成objc _ msgSend(id reciever,SEL sel,prarams1,params2,....)。所以上面的方法会被转换成:
         void objc_msgSend(zhangsan,@selector(goToSchoolWithPerson:),lisi);   //包含两个隐藏参数
         
         
         这里的 “v@:@”就代表:
         "v":代表返回值void
         "@":代表一个对象,这里指代的id类型zhangsan,也就是消息的receiver
         ":":代表SEL
         "@":代表参数lisi
         
         */
        
        //        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
        return [NSMethodSignature signatureWithObjCTypes:"v16@0:8"];
        
        
    }
    
    return [super methodSignatureForSelector:aSelector];
}

/*
 NSInvocation封装了一个方法调用,包括:方法调用者、方法名、方法参数
 anInvocation.target 方法调用者
 anInvocation.selector 方法名
 [anInvocation getArgument:NULL atIndex:0]
 
 你可以在这个函数里面干你想干的事
 
 */




- (void)forwardInvocation:(NSInvocation *)anInvocation{
    
    //1、你可以转发消息
    
    //    anInvocation.target = [[MJCat alloc] init];
    //    [anInvocation invoke];
    
    // 或
    //    [anInvocation invokeWithTarget:[[Student alloc] init]];
    
    
    //2、你可以干你想干的事。如:我就想打印
    NSLog(@"%s",__func__);
    
}

@end

由此可知:我们可以在三个地方来实现test方法

第一步:

+resolveInstanceMethod:(对象方法)
+resoveClassMethod:(类方法)

第二步:

forwardingTargetForSelector:  

第三步:

methodSignatureForSelector:aSelector
forwardInvocation:anInvocation

面试题 :什么是Runtime?平时项目中有用过么?

1、OC是一门动态性比较强的编程语言,允许很多操作推迟到程序运行时再进行
2、OC的动态性就是由Runtime来支撑和实现的,Runtime是一套C语言的API,封装了很多动态性相关的函数
3、平时编写的OC代码,底层都是转换成了Runtime API进行调用

具体应用

1、利用关联对象(AssociatedObject)给分类添加属性
2、遍历类的所有成员变量(修改textfield的占位文字颜色、字典转模型、自动归档解档)
3、交换方法实现(交换系统的方法)
4、利用消息转发机制解决方法找不到的异常问题

举例1:
1、窥探 系统自带对象的私有属性:如窥探UITextField 的属性
我们可以根据需求找到你想要的东西 然后去重写它等等

   UITextField * textField = [[UITextField alloc]init];
    // 成员变量的数量
    unsigned int count;
    Ivar *ivars = class_copyIvarList([UITextField class], &count);
    for (int i = 0; i < count; i++) {
        // 取出i位置的成员变量
        Ivar ivar = ivars[i];
        NSLog(@"%s %s", ivar_getName(ivar), ivar_getTypeEncoding(ivar));
    }
    free(ivars);

打印结果如下:

2021-01-20 10:06:44.646507+0800 LLLL[51081:1190161] _borderStyle q
2021-01-20 10:06:44.646605+0800 LLLL[51081:1190161] _minimumFontSize d
2021-01-20 10:06:44.646655+0800 LLLL[51081:1190161] _delegate @
2021-01-20 10:06:44.646713+0800 LLLL[51081:1190161] _background @"UIImage"
2021-01-20 10:06:44.646786+0800 LLLL[51081:1190161] _disabledBackground @"UIImage"
2021-01-20 10:06:44.646871+0800 LLLL[51081:1190161] _clearButtonMode q
2021-01-20 10:06:44.646929+0800 LLLL[51081:1190161] _leftView @"UIView"
2021-01-20 10:06:44.647006+0800 LLLL[51081:1190161] _leftViewMode q
2021-01-20 10:06:44.647095+0800 LLLL[51081:1190161] _rightView @"UIView"
2021-01-20 10:06:44.647180+0800 LLLL[51081:1190161] _rightViewMode q
2021-01-20 10:06:44.647274+0800 LLLL[51081:1190161] _contentCoverView @"UIView"
2021-01-20 10:06:44.647478+0800 LLLL[51081:1190161] _contentCoverViewMode q
2021-01-20 10:06:44.647650+0800 LLLL[51081:1190161] _backgroundCoverView @"UIView"
2021-01-20 10:06:44.647801+0800 LLLL[51081:1190161] _backgroundCoverViewMode q
2021-01-20 10:06:44.647988+0800 LLLL[51081:1190161] _traits @"UITextInputTraits"
2021-01-20 10:06:44.648146+0800 LLLL[51081:1190161] _nonAtomTraits @"UITextInputTraits"
2021-01-20 10:06:44.648569+0800 LLLL[51081:1190161] _fullFontSize @"_UIFullFontSize"
2021-01-20 10:06:44.648924+0800 LLLL[51081:1190161] _padding {UIEdgeInsets="top"d"left"d"bottom"d"right"d}
2021-01-20 10:06:44.649360+0800 LLLL[51081:1190161] _progress f
2021-01-20 10:06:44.649453+0800 LLLL[51081:1190161] _clearButton @"_UITextFieldClearButton"
2021-01-20 10:06:44.649528+0800 LLLL[51081:1190161] _clearButtonOffset {CGSize="width"d"height"d}
2021-01-20 10:06:44.649603+0800 LLLL[51081:1190161] _leftViewOffset {CGSize="width"d"height"d}
2021-01-20 10:06:44.649669+0800 LLLL[51081:1190161] _rightViewOffset {CGSize="width"d"height"d}
2021-01-20 10:06:44.665169+0800 LLLL[51081:1190161] _backgroundView @"UITextFieldBorderView"
2021-01-20 10:06:44.665276+0800 LLLL[51081:1190161] _disabledBackgroundView @"UITextFieldBorderView"
2021-01-20 10:06:44.665369+0800 LLLL[51081:1190161] _systemBackgroundView @"UITextFieldBackgroundView"
2021-01-20 10:06:44.665453+0800 LLLL[51081:1190161] _textContentView @"_UITextFieldCanvasView"
2021-01-20 10:06:44.665945+0800 LLLL[51081:1190161] _floatingContentView @"_UIFloatingContentView"
2021-01-20 10:06:44.666024+0800 LLLL[51081:1190161] _contentBackdropView @"UIVisualEffectView"
2021-01-20 10:06:44.666107+0800 LLLL[51081:1190161] _fieldEditorBackgroundView @"_UIDetachedFieldEditorBackgroundView"
2021-01-20 10:06:44.666174+0800 LLLL[51081:1190161] _fieldEditorEffectView @"UIVisualEffectView"
2021-01-20 10:06:44.666241+0800 LLLL[51081:1190161] _placeholderLabel @"UITextFieldLabel"
2021-01-20 10:06:44.666313+0800 LLLL[51081:1190161] _suffixLabel @"UITextFieldLabel"
2021-01-20 10:06:44.666406+0800 LLLL[51081:1190161] _prefixLabel @"UITextFieldLabel"
2021-01-20 10:06:44.666497+0800 LLLL[51081:1190161] _iconView @"UIImageView"
2021-01-20 10:06:44.666576+0800 LLLL[51081:1190161] _label @"UILabel"
2021-01-20 10:06:44.666659+0800 LLLL[51081:1190161] _labelOffset d
2021-01-20 10:06:44.666745+0800 LLLL[51081:1190161] _overriddenPlaceholder @"NSAttributedString"
2021-01-20 10:06:44.666833+0800 LLLL[51081:1190161] _overriddenPlaceholderAlignment q
2021-01-20 10:06:44.666997+0800 LLLL[51081:1190161] _interactionAssistant @"UITextInteractionAssistant"
2021-01-20 10:06:44.667143+0800 LLLL[51081:1190161] _selectGestureRecognizer @"UITapGestureRecognizer"
2021-01-20 10:06:44.667323+0800 LLLL[51081:1190161] _fieldEditor @"UIFieldEditor"
2021-01-20 10:06:44.667865+0800 LLLL[51081:1190161] __textContainer @"NSTextContainer"
2021-01-20 10:06:44.667974+0800 LLLL[51081:1190161] __layoutManager @"_UIFieldEditorLayoutManager"
2021-01-20 10:06:44.668068+0800 LLLL[51081:1190161] _textStorage @"_UICascadingTextStorage"
2021-01-20 10:06:44.668145+0800 LLLL[51081:1190161] _linkTextAttributes @"NSDictionary"
2021-01-20 10:06:44.668221+0800 LLLL[51081:1190161] _pasteController @"UITextPasteController"
2021-01-20 10:06:44.668360+0800 LLLL[51081:1190161] _inputView @"UIView"
2021-01-20 10:06:44.668574+0800 LLLL[51081:1190161] _inputAccessoryView @"UIView"
2021-01-20 10:06:44.668765+0800 LLLL[51081:1190161] _recentsAccessoryView @"UIView"
2021-01-20 10:06:44.669371+0800 LLLL[51081:1190161] _systemInputViewController @"UISystemInputViewController"
2021-01-20 10:06:44.669459+0800 LLLL[51081:1190161] _atomBackgroundView @"UITextFieldAtomBackgroundView"
2021-01-20 10:06:44.669525+0800 LLLL[51081:1190161] _textDragDropSupport @"<UITextDragDropSupport>"
2021-01-20 10:06:44.669603+0800 LLLL[51081:1190161] _textItemDiscoverer @"_UITextItemDiscoverer"
2021-01-20 10:06:44.669681+0800 LLLL[51081:1190161] _textFieldFlags {?="verticallyCenterText"b1"isAnimating"b4"inactiveHasDimAppearance"b1"becomesFirstResponderOnClearButtonTap"b1"clearsPlaceholderOnBeginEditing"b1"adjustsFontSizeToFitWidth"b1"fieldEditorAttached"b1"canBecomeFirstResponder"b1"shouldSuppressShouldBeginEditing"b1"inResignFirstResponder"b1"undoDisabled"b1"explicitAlignment"b1"implementsCustomDrawing"b1"needsClearing"b1"suppressContentChangedNotification"b1"allowsEditingTextAttributes"b1"usesAttributedText"b1"backgroundViewState"b2"clearingBehavior"b2"overridePasscodeStyle"b1"shouldResignWithoutUpdate"b1"blurEnabled"b1"visualEffectViewEnabled"b1"disableFocus"b1"disableRemoteTextEditing"b1"allowsAttachments"b1"isReceivingDrop"b1"contentCoverUnsecuresText"b1"forcesClearButtonHighContrastAppearance"b1"contentInsetsFromFontsValid"b1}
2021-01-20 10:06:44.669868+0800 LLLL[51081:1190161] _deferringBecomeFirstResponder B
2021-01-20 10:06:44.670089+0800 LLLL[51081:1190161] _animateNextHighlightChange B
2021-01-20 10:06:44.670723+0800 LLLL[51081:1190161] _cuiCatalog @"CUICatalog"
2021-01-20 10:06:44.671168+0800 LLLL[51081:1190161] _cuiStyleEffectConfiguration @"CUIStyleEffectConfiguration"
2021-01-20 10:06:44.671270+0800 LLLL[51081:1190161] _roundedRectBackgroundCornerRadius d
2021-01-20 10:06:44.671352+0800 LLLL[51081:1190161] _overriddenAttributesForEditing @"NSArray"
2021-01-20 10:06:44.671407+0800 LLLL[51081:1190161] _adjustsFontForContentSizeCategory B
2021-01-20 10:06:44.671486+0800 LLLL[51081:1190161] _tvUseVibrancy B
2021-01-20 10:06:44.671550+0800 LLLL[51081:1190161] _disableTextColorUpdateOnTraitCollectionChange B
2021-01-20 10:06:44.671659+0800 LLLL[51081:1190161] _pasteDelegate @"<UITextPasteDelegate>"
2021-01-20 10:06:44.671865+0800 LLLL[51081:1190161] _baselineLayoutConstraint @"NSLayoutConstraint"
2021-01-20 10:06:44.672058+0800 LLLL[51081:1190161] _baselineLayoutLabel @"_UIBaselineLayoutStrut"
2021-01-20 10:06:44.672269+0800 LLLL[51081:1190161] _tvCustomTextColor @"UIColor"
2021-01-20 10:06:44.672410+0800 LLLL[51081:1190161] _tvCustomFocusedTextColor @"UIColor"
2021-01-20 10:06:44.672573+0800 LLLL[51081:1190161] _textDragOptions q
2021-01-20 10:06:44.672777+0800 LLLL[51081:1190161] _textDragDelegate @"<UITextDragDelegate>"
2021-01-20 10:06:44.672989+0800 LLLL[51081:1190161] _textDropDelegate @"<UITextDropDelegate>"
2021-01-20 10:06:44.673218+0800 LLLL[51081:1190161] _visualStyle @"_UITextFieldVisualStyle"

举例2、字典转模型

好多第三方字典转模型 都会用到runtime  一般都是便利取出 模型(类)中的属性获取属性名称  然后经过一系列的复杂处理 得到一个字符串,最后经过 KVC来设置属性值 (可自行查看 三方字典转模型的内部实现)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容