12.2 谈谈Runtime的加载过程
https://www.jianshu.com/p/4fb2d7014e9e
runtime加载过程简述
runtime在加载的时候 ,通过dyld的一些操作,最终调用了runtime中的_objc_init函数,在这个函数中进行了一些初始化的操作,主要包括环境变量、线程方面、c++静态构造函数、异常处理。
紧接着注册了三个函数指针。map_Images load_images 和 unmap_Images.
map_images其实是一个函数中转。_read_images 是map_images内的一个核心函数
先整体梳理一遍_read_images函数内部的逻辑:
加载所有类到类的gdb_objc_realized_classes表中。
对所有类做重映射。
将所有SEL都注册到namedSelectors表中。
修复函数指针遗留。
将所有Protocol都添加到protocol_map表中。
对所有Protocol做重映射。
初始化所有非懒加载的类,进行rw、ro等操作。
遍历已标记的懒加载的类,并做初始化操作。
加载所有Category,然后根据方法类型处理Class和Meta Class。
初始化所有未初始化的类。
_read_images方法的详细分析
_load_images方法的详细分析
参考+(void)load方法详解
简单小结:
1. 类在内存中的位置是在编译期间决定的,在之后修改代码,也不会改变内存中的位置。
2. 类的方法、属性以及协议在编译期间存放到了“错误”的位置,直到 realizeClass 执行之后,才放到了 class_rw_t 指向的只读区域 class_ro_t,这样我们即可以在运行时为 class_rw_t 添加方法,也不会影响类的只读结构。
3. 在 class_ro_t 中的属性在运行期间就不能改变了,再添加方法时,会修改 class_rw_t 中的 methods 列表,而不是 class_ro_t 中的 baseMethods,对于方法的添加会在之后的文章中分析。