返回

iOS OC类底层objc_msgSend分析下(慢速查找流程)

IOS

引言

在上一篇文章中,我们详细探讨了 objc_msgSend 的快速查找流程,但尚未验证其正确性。因此,本文将创建一个 APP 工程,运行于真机上,查看汇编流程,深入剖析消息发送的底层原理。

慢速查找流程

当快速查找流程失败时,objc_msgSend 将转入慢速查找流程,具体流程如下:

  1. 创建 MethodList :为当前类创建一个 MethodList,存储该类及父类中所有方法的 Method 实例。
  2. 遍历 MethodList :逐一遍历 MethodList 中的方法,查找与 selector 匹配的方法。
  3. 查找 imp :对于匹配的方法,从 Method 中获取 imp 指针。
  4. 调用 imp :使用 imp 指针调用相应的方法。

汇编流程验证

为了验证慢速查找流程,我们创建了一个简单的 APP 工程,包含一个名为 Person 的类,该类定义了一个 sayHello 方法。

Person.h

@interface Person : NSObject

- (void)sayHello;

@end

Person.m

@implementation Person

- (void)sayHello {
    NSLog(@"Hello!");
}

@end

AppDelegate.m 中,我们发送一条 sayHello 消息给 Person 实例:

#import "Person.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    Person *person = [[Person alloc] init];
    [person sayHello];
    return YES;
}

@end

使用真机调试器运行该 APP,并设置断点于 objc_msgSend 函数。当程序运行到断点处时,查看汇编代码,可以看到慢速查找流程的实现:

; 创建 MethodList
mov  x0, #0x0                           // 类对象指针
bl   objc_copyMethodList                 // 拷贝方法列表
mov  x19, x0                            // 保存方法列表指针

; 遍历 MethodList
mov  x0, x19                            // 方法列表指针
mov  x1, #0x0                           // 索引
1:
ldp  x2, x3, [x0, x1, lsl #3]             // 获取 Method 实例
ldr  w2, [x2]                            // 获取 selector
cmp  w2, #0x0                           // selector 为空则遍历结束
bne  2f                                 // selector 不为空则继续遍历
add  x1, x1, #0x1                         // 索引 + 1
cmp  x1, x19                            // 索引与方法列表指针比较
ble  1b                                 // 索引小于等于方法列表指针,继续遍历

; 查找 imp
2:
ldp  x2, x3, [x0, x1, lsl #3]             // 获取 Method 实例
ldr  x0, [x2, #0x10]                      // 获取 imp 指针

; 调用 imp
mov  x0, x0                            // 保存 imp 指针
mov  x1, #0x0                           // 参数 1 为 self
blx  x0                                 // 调用 imp

结论

通过验证汇编流程,我们进一步加深了对 objc_msgSend 慢速查找流程的理解。慢速查找流程通过遍历 MethodList 查找与 selector 匹配的方法,并调用其 imp,实现了消息的动态分发。这种机制保证了 OC 代码的灵活性和可扩展性。