objc_msgSend 流程 1 - 缓存查找
本文对 Runtime 进行简单介绍 和对 objc_msgSend 的发消息流程中的缓存查找进行探索。
更新 (流程图概览):缓存查找流程图
我们知道类结构中包含了很多信息:isa superclass cache bits,cache 中缓存了我们调用的方法,具体流程见 OC 底层探索 07. 但是方法具体时间什么时候缓存的,需要继续探究。
源码 objc_cache.mm 文件,Method cache locking 中,我们可以看到在写入之前还有一个读的过程
–> objc_msgSend* / cache_getImp:
看到 objc_msgSend 就不免想到 runtime,我们先简单介绍下 runtime 是什么。
一、Runtime 简介
Runtime 是一个为我们 OC 语言开发中提供动态特性的一个库。
官方文档: Objective-C Runtime
/Objective-C Runtime Programming Guide
《The Objective-C language defers as many decisions as it can from compile time and link time to runtime. Whenever possible, it does things dynamically. This means that the language requires not just a compiler, but also a runtime system to execute the compiled code. The runtime system acts as a kind of operating system for the Objective-C language; it’s what makes the language work.》
OC 语言将尽可能多的决策从编译时和链接时延迟到运行时。只要有可能,它就动态地做事情。这意味着该语言不仅需要一个编译器,还需要一个运行时系统来执行编译后的代码。运行时系统作为 Objective-C 语言的一种操作系统;它使语言起作用。
提取信息点:一个提供动态特性的库,实现运行时作用。
1、Runtime 结构和调用方式:
complier: 编译 –> runtime 底层所调用的并非我们写的代码,它进过了 complier 进行编译、优化。 –> LLVM
tip:编译时、链接时,一句话简介 {
编译时:
1、对我们的代码进行语法词法等分析,并给出 waring、error 等提示。类似一个扫描过程,将代码扫一遍;
2、将编写的高级语言 (C C++ OC 等) 编译成机器识别的机器语言 (汇编、机器语言 01 等),编译得到相应的二进制目标文件。
编译时并没有进行加载分配内存等操作。
链接时:
将编译得到的二进制文件和库函数等进行连接。
运行时:
代码已被装载到内存中,已运行起来了。
}
2、探索
通过 clang 将 main.m 文件编译成 mian.cpp. mian 函数编译结果如下:
id objc_msgSend(id self, SEL _cmd, …) :
消息接受者 self;消息体 SEL. 通过查找 objc_msgSend() 源码,我们可以发现它是使用汇编实现的,这里暂时先不探究,继续当前操作。
sel_registerName(“helloObj1”):
注册一个方法。例: 上层的操作 @selector() / NSSelectorFromString() 都是 SEL 类型.
直接使用 API - objc_msgSend() 进行方法调用
对代码进行修改:
报错如下:
修改工程配置:Building Setting –> Preprocessing –> 将 objc_msgSend call 严格检查改为 NO.
运行结果如下,通过 objc_msgSend() 正常调用了方法’helloObj3’:
OC 方法调用 –> objc_msgSend() –> sel (方法编号) –> imp (函数指针地址) –> 函数.
sel 如何找到 imp 呢?
二、objc_msgSend 流程探索 - cache
从上面的操作,可知方法调用的本质是 发送消息,下面进行 发送消息流程的探究。
全局查找 objc_msgSend(),是通过汇编实现的
使用汇编的原因:
1、快速,方法的查找操作是很频繁的,汇编是相对底层的语言更易被机器识别,节省中间的一些编译过程。
2、语言的动态特性,C/C++ 来编写实现的话更偏向于静态,虽然也可实现会更麻烦且慢。
下面我们通过源码 注释 和 网络 对消息查找流程进行探索。
objc_msgSend 流程
消息接收者 和 sel:
消息接受者 –> 对象 –> isa –> 方法 (类 / 元类) –> cache_t –> methodliss(bits 中)
主要流程源码 CacheLookup:(汇编指令解读)
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!