返回
iOS OC类底层objc_msgSend分析下(慢速查找流程)
IOS
2023-11-22 22:46:07
引言
在上一篇文章中,我们详细探讨了 objc_msgSend 的快速查找流程,但尚未验证其正确性。因此,本文将创建一个 APP 工程,运行于真机上,查看汇编流程,深入剖析消息发送的底层原理。
慢速查找流程
当快速查找流程失败时,objc_msgSend 将转入慢速查找流程,具体流程如下:
- 创建 MethodList :为当前类创建一个 MethodList,存储该类及父类中所有方法的 Method 实例。
- 遍历 MethodList :逐一遍历 MethodList 中的方法,查找与 selector 匹配的方法。
- 查找 imp :对于匹配的方法,从 Method 中获取 imp 指针。
- 调用 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 代码的灵活性和可扩展性。