本文为L_Ares个人写作,以任何形式转载请表明原文出处。
本文需要objc4-781源码作为辅助探索。
_objc_init中前两个函数参数一个是map_images,一个就是本节要说的load_images。map_images的内容前面的十五、十六节主要探索了类的加载,上一节正好因为分类说到了load_images。而且之前的探索我们发现了+(void)load方法调用的很早,所以也需要知道+(void)load方法到底是什么时候调用的。所以本节探索load_images。
load_images函数主要的作用 :
加载镜像文件。调用
+(void)load方法。这里注意,一定是非懒加载的类才会调用,因为懒加载的类是不调用+(void)load方法的。
load_images的调用是在+(void)load方法之前,为什么这么说?随便实现一个类的+(void)load方法,最好NSLog点东西,然后在main.m中初始化这个类。
然后我们在load_images源码里面随意打一个断点,会发现NSLog的东西是没有打印的。

图片.png
那么 看一下load_images的源码

图1.0.0.png
发现两个比较重要的方法
prepare_load_methods: 发现load,对其进行准备。call_load_methods: 调用load方法。
一、prepare_load_methods
进入之后找到上面的注释这里。
1. 类的load方法添加到表

图片.png
- 这里主要就是根据类的继承链递归获取
+(void)load方法,然后存入表里面。
递归的结束条件是cls的父类已经为nil了。
进入添加到表的那一步add_class_to_loadable_list源码 :

图片.png
- 获取类
cls的load方法,然后把cls---load存储到loadable_classes表中。
再看一下cls是怎么获得load方法的,进入getLoadMethod()源码 :

图片.png
- 就是通过
sel == load,找到load的imp。
2. 分类的load方法添加到表
然后我们回到最开始要看的prepare_load_methods

图片.png
- 将非懒加载的分类添加到表中。

图片.png
二、call_load_methods
/***********************************************************************
* call_load_methods
* Call all pending class and category +load methods. 调起所有挂起的类和分类的+load方法
* Class +load methods are called superclass-first. 父类的+load方法要先调用
* Category +load methods are not called until after the parent class's +load. 分类的+load方法要等到父类的+load调用完成后再调用
*
* This method must be RE-ENTRANT, because a +load could trigger
* more image mapping. In addition, the superclass-first ordering
* must be preserved in the face of re-entrant calls. Therefore,
* only the OUTERMOST call of this function will do anything, and
* that call will handle all loadable classes, even those generated
* while it was running.
*
* The sequence below preserves +load ordering in the face of
* image loading during a +load, and make sure that no
* +load method is forgotten because it was added during
* a +load call.
* Sequence:
* 1. Repeatedly call class +loads until there aren't any more //反复调用类的+load方法,一直到没有
* 2. Call category +loads ONCE. //分类的+load方法只调用一次
* 3. Run more +loads if: //多次执行+load方法的条件
* (a) there are more classes to load, OR //有很多的类都要调用load方法
* (b) there are some potential category +loads that have //有些潜在的分类的load方法还没有调用过
* still never been attempted.
* Category +loads are only run once to ensure "parent class first" //分类的+load方法只跑一次是为了确保父类优先的原则
* ordering, even if a category +load triggers a new loadable class //就算分类的+load方法中触发了一个新的拥有+load方法的类和它的带有+load方法的分类
* and a new loadable category attached to that class.
*
* Locking: loadMethodLock must be held by the caller
* All other locks must not be held.
**********************************************************************/
void call_load_methods(void)
{
static bool loading = NO;
bool more_categories;
loadMethodLock.assertLocked();
// Re-entrant calls do nothing; the outermost call will finish the job.
if (loading) return;
loading = YES;
void *pool = objc_autoreleasePoolPush();
do {
// 1. Repeatedly call class +loads until there aren't any more
//循环调用类的+load方法,一直到类没有了
while (loadable_classes_used > 0) {
call_class_loads();
}
// 2. Call category +loads ONCE
//只调用一次分类的+load方法
more_categories = call_category_loads();
// 3. Run more +loads if there are classes OR more untried categories
//如果有很多的类或者一次都没有尝试调用过的分类,那么就会把这些+load方法都调用。
} while (loadable_classes_used > 0 || more_categories);
objc_autoreleasePoolPop(pool);
loading = NO;
}
注释翻译了一下,有兴趣的可以自行翻译。
主要做了三件事 :
- 循环调用类的
+load方法,除非类没有了- 只调用一次分类的
+load方法。- 如果还有更多的类或者没有尝试的分类,则会调用更多的
+load方法。
1. call_class_loads
那么主要的一点就是call_class_loads,看一下怎么调用的类的+(void)load方法

图片.png
还有一点就是call_category_loads

图片.png
三、总结
直接上图。
load_images流程图

load_images流程图.png