iOS进阶—Runtime:OC方法底层调用过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wtdask/article/details/84140222

GitHub参考
PS:参考GitHub分享的Runtime002代码

iOS进阶—目录


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)

猜你喜欢

转载自blog.csdn.net/wtdask/article/details/84140222