GitHub参考
PS:参考GitHub分享的Runtime002代码
OC方法底层调用过程
如果查看OC的底层调用过程,我们需要借助clang工具
使用终端
cd 项目目录
clang -rewrite-objc main.m
会生成一个main.cpp文件

添加进项目当中,注意不要选择编译选项,如下图

我们查看main.cpp文件当中main函数的实现

我们把其中关注的代码复制过来,如下((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("walk")); 与[p walk];是等价的。
#import <Foundation/Foundation.h>
#import "TZPerson.h"
#import <objc/message.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
TZPerson * p =[TZPerson new];
// [p walk];
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("walk"));
}
return 0;
}
把上面的强转代码删除,对其简化如下:objc_msgSend(p, sel_registerName("walk"));
注意:去掉强转类型,需要做如下设置,编译预处理时,去掉严格审查功能,才能运行

我们编写代码NSLog(@"%p,%p",@selector(walk),sel_registerName("walk"));查看,输出
2018-11-16 15:23:41.477798+0800 Runtime001[4290:154325] 0x100000f9d,0x100000f9d
2018-11-16 15:23:41.478135+0800 Runtime001[4290:154325] -[TZPerson walk]
Program ended with exit code: 0
可以看到两种代码的执行地址是一模一样的,所以得出结论sel_registerName("walk")) = @selector(walk)
其实类消息发送也是一样的,代码如下:
#import <Foundation/Foundation.h>
@interface TZPerson : NSObject
- (void) walk;
+ (void) run;
@end
[TZPerson run];
objc_msgSend(objc_getClass("TZPerson"), @selector(run));
所以,我们得出结论:OC方法调用的本质msg_Send,就是需要消息接收者objc_getClass("TZPerson")和消息名称@selector(run)
本文深入探讨了Objective-C中方法调用的本质,通过实例解析了如何使用clang工具查看底层调用过程,揭示了objc_msgSend与OC方法调用之间的联系。

1万+

被折叠的 条评论
为什么被折叠?



