和谐学习!不急不躁!!我是你们的老朋友小青龙~
前一篇文章iOS底层分析之类的加载(中)分析了ro、rw的初始化以及分类的本质,本文针对分类的加载
展开进一步的探究。
上篇文章,我们分析到:rwe的初始化是在extAllocIfNeeded函数
,调用extAllocIfNeeded函数有好几个地方:
-
attachCategories
函数(将类别的属性、协议、方法添加到类) -
demangledName函数
-
class_setVersion函数(类的版本设置)
-
addMethods_finish函数(添加方法)
-
class_addProtocol函数(添加协议)
-
_class_addProperty函数(添加属性)
-
objc_duplicateClass函数
添加属性、方法、协议等会调用extAllocIfNeeded函数,让我不禁想到了文章《iOS类里面的数据为什么要分为ro、rw、rwe?》的一句话:
- 由于
运行时
的存在,Methods、Protocols、Properties都是可以通过category
或手动使用API
,动态添加、修改,所以rw里也存了一份这些数据。
而rwe是rw的优化,所以可以理解为:
category
或手动使用API
修改/添加Methods、Protocols、Properties等会触发extAllocIfNeeded函数,从而给rwe赋值。
回归正题,我们要探究的是跟category有关的,核心函数是attachCategories
,而调用到attachCategories的函数有两个:
- attachToClass
- load_categories_nolock
查看哪里调用了attachToClass
objc源码
搜索attachToClass
,发现只有methodizeClass这个函数内部调用了:
这里有个if判断,我们需要知道previously
值,发现它是由methodizeClass
函数第二个参数传进来的。
继续搜索methodizeClass
:
跟上面一样,也是函数之间参数的传递,继续搜索realizeClassWithoutSwift
:
把上面寻找的过程画了个图:
回到methodizeClass
函数(参数previously为nil
):
static void methodizeClass(Class cls, Class previously){
...
// 经过上传的探索,确认previously为nil
if (previously) {
if (isMeta) {
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_METACLASS);
} else {
objc::unattachedCategories.attachToClass(cls, previously,
ATTACH_CLASS_AND_METACLASS);
}
}
objc::unattachedCategories.attachToClass(cls, cls,
isMeta ? ATTACH_METACLASS : ATTACH_CLASS);
...
}
复制代码
等于说调用attachToClass
的地方只有这一个地方:
static void methodizeClass(Class cls, Class previously){
...
objc::unattachedCategories.attachToClass(cls, cls,
isMeta ? ATTACH_METACLASS : ATTACH_CLASS);
...
}
复制代码
查看哪里调用了load_categories_nolock
objc源码
搜索load_categories_nolock
,发现这有这两个地方调用了:
- loadAllCategories
- _read_images
static void loadAllCategories() {
...
load_categories_nolock(hi);
...
}
void _read_images(header_info **hList, uint32_t hCount, int totalClasses, int unoptimizedTotalClasses){
...
load_categories_nolock(hi);
...
}
复制代码
整理一下调用attachCategories的两条线:
-
realizeClassWithoutSwift -> methodizeClass -> attachToClass -> attachCategories
-
load_categories_nolock -> attachCategories
category的load方法实现与否
我们知道,Class根据是否实现load方法,分为懒加载类和非懒加载类,那么category是否也有这样的区分呢?
根据前面分析,调用attachCategories
的地方分别是realizeClassWithoutSwift
和load_categories_nolock
。我们在这几个地方打上断点:
测试一:主类实现load方法,category实现load方法
运行代码:
所以我们得出这样一条走向路线: