面试题答案
一键面试消息转发流程
- 动态方法解析:
- 当对象接收到无法识别的消息时,首先进入动态方法解析阶段。运行时系统会调用类方法
+ (BOOL)resolveInstanceMethod:(SEL)sel
(针对实例方法)或+ (BOOL)resolveClassMethod:(SEL)sel
(针对类方法)。 - 在这个方法中,开发者可以通过
class_addMethod
函数向类中动态添加方法实现。如果成功添加方法,返回YES
,则消息传递继续执行新添加的方法;如果返回NO
,则进入备用接收者阶段。
- 当对象接收到无法识别的消息时,首先进入动态方法解析阶段。运行时系统会调用类方法
- 备用接收者:
- 如果动态方法解析没有处理消息,运行时系统会调用
-(id)forwardingTargetForSelector:(SEL)aSelector
方法。 - 该方法返回一个对象,如果返回的对象不为
nil
,则将消息转发给这个对象处理,这个对象成为备用接收者。如果返回nil
,则进入完整转发阶段。
- 如果动态方法解析没有处理消息,运行时系统会调用
- 完整转发:
- 首先,运行时系统会调用
-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
方法。- 该方法返回一个
NSMethodSignature
对象,描述了被调用方法的参数和返回值类型等信息。如果返回nil
,则会调用doesNotRecognizeSelector:
方法,程序抛出异常并终止。
- 该方法返回一个
- 若
methodSignatureForSelector:
方法返回了有效的NSMethodSignature
对象,运行时系统会接着调用-(void)forwardInvocation:(NSInvocation *)anInvocation
方法。- 在这个方法中,开发者可以通过
NSInvocation
对象重新指定消息的目标对象,修改参数,然后调用invokeWithTarget:
方法来执行消息。
- 在这个方法中,开发者可以通过
- 首先,运行时系统会调用
实际项目场景及优势
- 场景一:代理模式的实现
- 场景描述:在一个 iOS 应用开发项目中,例如一个自定义视图需要将某些事件通知给它的上级视图控制器。
- 优势:可以通过消息转发机制实现类似代理的功能。自定义视图可以将未处理的消息转发给它的代理对象(通常是上级视图控制器)。这样做的优势在于,代码结构更加清晰,自定义视图和代理对象之间的耦合度降低。视图专注于自身的绘制和交互逻辑,而代理对象专注于处理视图传递过来的事件,提高了代码的可维护性和可扩展性。
- 场景二:模拟多继承
- 场景描述:在一个复杂的 iOS 应用中,某个类可能需要复用多个其他类的功能,但 Objective - C 不支持多继承。
- 优势:通过消息转发机制,这个类可以将无法处理的消息转发给多个不同功能的类。例如,一个
HybridViewController
类可能需要复用NetworkManager
类的网络请求功能和DataParser
类的数据解析功能。它可以在forwardingTargetForSelector:
方法中根据不同的选择器(SEL),将消息转发给NetworkManager
或DataParser
实例,从而实现类似多继承的效果,避免了类层次结构的复杂性,提高了代码的复用性。
- 场景三:异常处理和调试
- 场景描述:在开发大型 iOS 项目时,可能会存在一些未处理的消息发送情况。
- 优势:在完整转发阶段,如果
methodSignatureForSelector:
返回nil
,会调用doesNotRecognizeSelector:
方法。开发者可以在这个方法中进行异常捕获和日志记录,方便定位和修复问题。同时,在forwardInvocation:
方法中,可以对转发的消息进行一些额外的处理,如记录方法调用的参数和返回值,用于调试和性能分析。