iOS底层分析之类的加载(下)

和谐学习!不急不躁!!我是你们的老朋友小青龙~

前一篇文章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这个函数内部调用了:

image.png

这里有个if判断,我们需要知道previously值,发现它是由methodizeClass函数第二个参数传进来的。

继续搜索methodizeClass

image.png

跟上面一样,也是函数之间参数的传递,继续搜索realizeClassWithoutSwift

image.png

把上面寻找的过程画了个图:

001.png

回到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的地方分别是realizeClassWithoutSwiftload_categories_nolock。我们在这几个地方打上断点:

image.png

image.png

image.png

测试一:主类实现load方法,category实现load方法

运行代码:

image.png

001.png

002.png

003.png

004.png

005.png

所以我们得出这样一条走向路线:

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享