面试题答案
一键面试Objective-C的Runtime消息转发机制完整流程
- 动态方法解析
- 当向一个对象发送一条它无法识别的消息时,首先进入动态方法解析阶段。
- 对于实例方法,运行时系统会调用类方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
,开发者可以在这个方法中动态添加方法实现。例如,可以使用class_addMethod
函数动态为类添加一个实例方法。 - 对于类方法,运行时系统会调用
+ (BOOL)resolveClassMethod:(SEL)sel
,同样可以在这个方法中使用class_addMethod
动态添加类方法的实现。
- 备用接收者
- 如果动态方法解析阶段没有处理消息,那么进入备用接收者阶段。
- 运行时系统会调用
-(id)forwardingTargetForSelector:(SEL)aSelector
方法,在这个方法中,开发者可以返回一个能处理该消息的对象。如果返回非nil
对象,那么消息会被转发给这个对象处理;如果返回nil
,则进入完整的消息转发阶段。
- 完整的消息转发
- 首先,运行时系统会创建一个
NSInvocation
对象,它封装了消息的参数、选择子和目标对象等信息。 - 然后调用
-(void)forwardInvocation:(NSInvocation *)anInvocation
方法,在这个方法中,开发者可以手动指定将消息转发给哪个对象处理。可以通过[anInvocation setTarget:newTarget]
重新设置消息的目标对象,然后调用[anInvocation invoke]
来触发消息的执行。 - 如果
forwardInvocation:
方法没有处理消息,那么运行时系统会调用-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
方法来获取方法签名。如果这个方法返回nil
,则会抛出unrecognized selector sent to instance
异常;如果返回有效的方法签名,那么会再次调用forwardInvocation:
方法来处理消息。
- 首先,运行时系统会创建一个
关联对象在Runtime中的实现原理
- 实现原理
- 关联对象是通过
objc_setAssociatedObject
、objc_getAssociatedObject
和objc_removeAssociatedObjects
这几个函数来实现的。 - 每个对象都有一个独立的
AssociationsManager
,它管理着一个全局的AssociationsHashMap
。这个哈希表以对象的内存地址作为键,以另一个哈希表ObjectAssociationMap
作为值。 ObjectAssociationMap
以关联对象的key
(通常是一个NSString
或者void *
类型的唯一标识)作为键,以ObjectAssociation
结构体作为值。ObjectAssociation
结构体存储了关联对象的引用策略(如OBJC_ASSOCIATION_ASSIGN
、OBJC_ASSOCIATION_RETAIN_NONATOMIC
等)和关联对象本身。
- 关联对象是通过
- 应用场景
- 给分类添加属性:在Objective - C中,分类不能直接添加实例变量,但可以通过关联对象为分类添加属性。例如,为
UIView
分类添加一个自定义的属性来存储额外的数据。 - 临时附加数据:在某些情况下,需要为对象临时附加一些数据,而不需要在类的定义中添加属性。比如在视图控制器的跳转过程中,临时为某个视图控制器对象附加一些传递的数据。
- 给分类添加属性:在Objective - C中,分类不能直接添加实例变量,但可以通过关联对象为分类添加属性。例如,为