返回

深扒 OC 消息快慢转发原理,揭秘其背后的流程

IOS

消息转发:Objective-C 的动态消息处理机制

在 Objective-C 的世界中,消息转发是一项至关重要的机制,它赋予对象在运行时动态处理未实现消息的能力。它充当了一个救生员,在接收者不知道如何处理某个特定消息时,确保消息仍然可以得到处理。消息转发有两种主要类型:快转发和慢转发,它们提供了不同的消息转发方式。

快转发:直接命中目标

快转发是一种快速高效的消息转发机制,它直接在接收者类中查找与消息选择器相匹配的方法。就像一个训练有素的弓箭手,它直接命中目标,不需要多余的步骤。

  1. 当接收者收到一个未实现的消息时,系统会寻找该对象的 isa 指向的类。
  2. 系统在该类中查找与消息选择器匹配的方法。
  3. 如果找到匹配的方法,它就会直接调用该方法,完成任务。

代码示例:

@implementation MyClass

- (void)myMethod {
    // 方法实现
}

@end

如果一个 MyClass 对象收到一个 myMethod 消息,快转发将直接调用 - (void)myMethod 方法。

慢转发:迂回前进

慢转发是一种更通用的消息转发机制,它需要一个更迂回的路径来找到合适的处理方法。就像一个侦探,它会遍历所有可能的线索,直到找到答案。

  1. 当接收者收到一个未实现的消息时,系统会寻找该对象的 isa 指向的类。
  2. 系统遍历该类的所有父类,直到找到与消息选择器匹配的方法或到达 NSObject 类。
  3. 如果找到匹配的方法,它就会调用该方法。
  4. 否则,执行慢转发,即寻找实现了 - (id)forwardingTargetForSelector:(SEL)aSelector 方法的对象。
  5. 将消息转发给该对象,它可以再次进行慢转发或快转发,直到找到合适的处理方法。

代码示例:

@implementation MyClass

- (id)forwardingTargetForSelector:(SEL)aSelector {
    // 返回一个可以处理该消息的对象
}

@end

如果一个 MyClass 对象收到一个未实现的消息,慢转发将首先查找 - (id)forwardingTargetForSelector:(SEL)aSelector 方法,并将消息转发给它返回的对象。

反汇编 CoreFoundation:深入底层

为了深入了解消息快慢转发的底层实现,我们可以反汇编 CoreFoundation。它是一个 C 语言库,包含许多与 Objective-C 相关的函数。

快转发实现:

_objc_msgSend:
    mov     r0, r2      ; 获取接收者对象
    mov     r1, r3      ; 获取消息选择器
    ldr     r2, [r0]    ; 获取接收者类的 isa 指针
    mov     r3, r0      ; 将接收者对象传递给方法
    mov     r0, r2      ; 将类指针传递给方法
    blx     r2          ; 调用 isa 指针指向的方法

慢转发实现:

_objc_forward:
    mov     r0, r2      ; 获取接收者对象
    mov     r1, r3      ; 获取消息选择器
    ldr     r2, [r0]    ; 获取接收者类的 isa 指针
    blx     r2          ; 调用 isa 指针指向的 forwardingTargetForSelector 方法
    mov     r0, r0      ; 将 forwardingTargetForSelector 方法返回的对象传递给方法
    mov     r1, r1      ; 将消息选择器传递给方法
    blx     r0          ; 调用 forwardingTargetForSelector 方法返回的对象

结论:赋能动态消息处理

消息快慢转发机制为 Objective-C 对象提供了处理未实现消息的强大能力。它们为快速高效的处理(快转发)和更灵活通用的处理(慢转发)提供了不同的途径。通过理解这些机制的底层实现,我们可以编写更强大、更健壮的 Objective-C 代码,充分利用动态消息处理的优势。

常见问题解答

1. 什么时候应该使用快转发,什么时候应该使用慢转发?

  • 快转发: 当你知道接收者类中肯定有一个方法可以处理消息时。
  • 慢转发: 当消息处理逻辑更复杂,可能需要在不同的对象或类之间转发时。

2. - (id)forwardingTargetForSelector:(SEL)aSelector 方法做什么?

它允许你指定一个可以处理未实现消息的对象。

3. 慢转发可以无限进行吗?

否,慢转发有一个递归深度限制,以防止无限循环。

4. 如何调试消息转发问题?

你可以使用 @try/@catch 语句来捕获未处理的消息。

5. 消息转发机制是否会影响应用程序性能?

快转发几乎没有性能开销,而慢转发可能比直接调用方法慢一点。