版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wtdask/article/details/84140222
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)