iOS objc_msgSend 流程
2020-09-19 本文已影响0人
我要当个程序员
准备
- objc_msgSend链接: https://pan.baidu.com/s/116k--tNSuikvsiGE8oU48w 密码: wl56
Runtime吐槽
其实到现在我都不太能理解Runtime是什么,只能通俗的理解为:运行时。找了好几篇文档进行对比,什么静态语言,动态语言,我甚至也找了静态,动态语言的博客通读了一下。真的是一堆乱七八糟,都是复制粘贴+翻译来的吧!!
没办法,只能强制理解了,iOS里面的Runtime其实就是一些特别c/c++
的api函数,用来装b。至于他有什么b用,我不知道,等我后面学习到了,在补上。
objc_msgSend是什么
objc_msgSend
就是我所说Runtime中一些特别c/c++
的api函数,其定义在#import <objc/message.h>
,那么为什么要研究它呢?
打开我们的准备好的项目工程,在LGPerson中写一个test01
函数方法,然后在main.m
中调用
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
appDelegateClassName = NSStringFromClass([AppDelegate class]);
LGPerson *p = [LGPerson alloc];
[p test01];
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
通过clang将我们的main.m
文件编译成底层c/c++
文件,来查看
//main.m文件所在的终端中输入
xcrun -sdk iphonesimulator clang -rewrite-objc main.m
这时候将会把我们的main.m
编译成main.cpp
,打开main.cpp
并滑动到最底层
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
/* @autoreleasepool */
{ __AtAutoreleasePool __autoreleasepool;
appDelegateClassName = NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class")));
Person *p = ((Person *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("Person"), sel_registerName("alloc"));
((void (*)(id, SEL))(void *)objc_msgSend)((id)p, sel_registerName("test01"));
}
return UIApplicationMain(argc, argv, __null, appDelegateClassName);
}
由此可见,Xocde将oc的代码编译成c/c++
文件。而我们oc中的调用方法是通过底层objc_msgSend
函数来执行。
objc_msgSend参数和调用
在<objc/message.h>
中可知
objc_msgSend("对象","SEL","参数"...)
objc_msgSend( id self, SEL op, ... )
LGPerson *p = [LGPerson alloc];
//这两个是相等的,你们可以自己试一下
[p test01];
objc_msgSend(p,sel_registerName("test01"));
objc_msgSend流程分析
打开我们的准备好的项目工程,苹果开发者为了快速,所以objc_msgSend
的函数实现是通过汇编的方式来写的。
ENTRY
汇编函数的实现进入,具体的里面的代码就不带大家看了,你们可以自己打开工程点击进去看,这里开始梳理一下objc_msgSend
的流程
1、objc_msgSend( id self, SEL op, ... )
2、ENTRY _objc_msgSend
3、对消息接受者(self,sel)判断处理
4、taggedPointer 判断处理
5、CacheLookup查找混存
6、cache_t处理,bucket以及内存哈希处理
6.1找不到递归下一个bucket
6.2找到返回
6.3遇到意外重试
6.4找不到 JumpMiss
7、__objc_msgSend_uncached 找不到缓存imp
8、MethodTableLookup 到isa里的bits.data()去查找
这里有一份:详细objc_msgSend流程研究