第十七节—load_images

本文为L_Ares个人写作,以任何形式转载请表明原文出处。

本文需要objc4-781源码作为辅助探索。

_objc_init中前两个函数参数一个是map_images,一个就是本节要说的load_imagesmap_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
  • 获取类clsload方法,然后把cls---load存储到loadable_classes表中。

再看一下cls是怎么获得load方法的,进入getLoadMethod()源码 :

图片.png
  • 就是通过sel == load,找到loadimp

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

你可能感兴趣的:(第十七节—load_images)