面试题答案
一键面试动态方法解析(Dynamic Method Resolution)
- 触发情况:当向一个对象发送一条它无法识别的消息时,首先会进入动态方法解析阶段。
- 具体操作:
- 对于实例方法,运行时会调用
+ (BOOL)resolveInstanceMethod:(SEL)sel
方法,类可以在这个方法中动态添加实例方法的实现。比如通过class_addMethod
函数将方法实现添加到类中。 - 对于类方法,运行时会调用
+ (BOOL)resolveClassMethod:(SEL)sel
方法,同样可以通过class_addMethod
函数添加类方法的实现。如果在这个阶段成功添加了方法实现,消息转发流程结束,消息会被重新发送并得到处理;如果没有添加成功,则进入下一个阶段。
- 对于实例方法,运行时会调用
备用接收者(Fast Forwarding)
- 触发情况:在动态方法解析阶段没有为消息找到处理方法时,会进入备用接收者阶段。
- 具体操作:运行时会调用
- (id)forwardingTargetForSelector:(SEL)aSelector
方法。如果该方法返回一个非nil
对象,那么这个对象会作为备用接收者来处理这条消息,消息转发流程结束。如果返回nil
,则继续进入完整的消息转发阶段。
完整的消息转发(Normal Forwarding)
- 触发情况:当备用接收者阶段没有找到合适的备用接收者时,进入完整的消息转发阶段。
- 具体操作:
- 首先,运行时会创建一个
NSInvocation
对象,该对象包含了原始的消息、目标对象和参数等信息。然后调用- (void)forwardInvocation:(NSInvocation *)anInvocation
方法。 - 在
forwardInvocation:
方法中,开发者可以手动将消息转发给其他对象处理。比如找到一个能处理该消息的对象otherTarget
,通过[anInvocation setTarget:otherTarget]
设置新的目标,然后[anInvocation invoke]
来执行消息。 - 如果
forwardInvocation:
方法没有处理该消息,运行时会调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
方法来获取方法签名。如果该方法返回nil
,则会抛出unrecognized selector sent to instance
异常;如果返回有效的方法签名,运行时会再次调用forwardInvocation:
方法让开发者处理消息。
- 首先,运行时会创建一个