MST

星途 面试题库

面试题:Objective-C 反射机制下的动态方法解析与消息转发

当向一个对象发送一个它并不直接响应的消息时,Objective-C 是如何通过反射机制来处理这种情况的?请详细描述动态方法解析、备用接收者以及完整的消息转发流程,并说明这一机制在实际项目中的应用场景和优势。
10.8万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

动态方法解析

  1. 类方法解析:当对象接收到无法识别的消息时,运行时系统首先会调用类方法 + (BOOL)resolveClassMethod:(SEL)sel。如果该类实现了此方法,可以在这个方法中动态添加类方法的实现。例如:
+ (BOOL)resolveClassMethod:(SEL)sel {
    if (sel == @selector(aClassMethod)) {
        class_addMethod(self, sel, (IMP)aClassMethodImplementation, "v@:");
        return YES;
    }
    return [super resolveClassMethod:sel];
}
  1. 实例方法解析:如果类方法解析未处理该消息,运行时会调用实例方法 + (BOOL)resolveInstanceMethod:(SEL)sel。同样,可以在这个方法中动态添加实例方法的实现。例如:
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    if (sel == @selector(anInstanceMethod)) {
        class_addMethod(self, sel, (IMP)anInstanceMethodImplementation, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}

备用接收者

如果动态方法解析没有处理该消息,运行时会尝试寻找备用接收者。它会调用 -(id)forwardingTargetForSelector:(SEL)aSelector 方法。在这个方法中,可以返回一个能够响应这个消息的对象。例如:

- (id)forwardingTargetForSelector:(SEL)aSelector {
    if ([otherObject respondsToSelector:aSelector]) {
        return otherObject;
    }
    return nil;
}

完整的消息转发流程

  1. 动态方法解析:运行时首先尝试动态解析方法,调用 + (BOOL)resolveClassMethod:(SEL)sel+ (BOOL)resolveInstanceMethod:(SEL)sel,看是否能动态添加方法实现。
  2. 备用接收者:如果动态方法解析未处理,运行时调用 -(id)forwardingTargetForSelector:(SEL)aSelector 寻找备用接收者。
  3. 完整转发:如果前两步都未处理,进入完整转发阶段。首先调用 -(void)forwardInvocation:(NSInvocation *)anInvocation,在这个方法中,可以重新设置 anInvocation 的目标对象,让其指向能处理该消息的对象,然后调用 [anInvocation invoke] 来执行消息。如果 forwardInvocation: 也未处理,最后会调用 -(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector 来获取方法签名,如果获取到签名,会再次调用 forwardInvocation:,若未获取到签名,会抛出 unrecognized selector 异常。

应用场景

  1. 框架设计:在设计框架时,某些功能可能在运行时才确定具体实现,通过反射机制可以实现灵活的功能扩展。例如,一个网络请求框架,可能在运行时根据不同的服务器响应决定调用不同的解析方法,通过动态方法解析可以在运行时添加相应的解析方法。
  2. 代码简洁性:在一些情况下,多个对象可能有相似的功能但并不属于同一个继承体系。通过备用接收者和消息转发,可以避免重复代码。比如,在一个复杂的用户界面中,不同的视图控制器可能有一些相同的辅助功能,通过消息转发可以将这些功能集中到一个辅助对象中处理。

优势

  1. 灵活性:使得程序在运行时能够根据实际情况动态调整行为,而不需要在编译时就确定所有的方法调用,提高了代码的灵活性和可扩展性。
  2. 代码复用:备用接收者和消息转发机制可以避免在不同类中重复实现相同功能,提高了代码的复用性,减少了代码冗余。
  3. 优雅的接口设计:在框架设计中,反射机制有助于提供简洁、易用的接口,让开发者可以在运行时灵活地定制功能,而不需要修改框架的核心代码。