iOS 类的加载(下)

2021-02-15  本文已影响0人  辉辉岁月

在上一篇文章类的加载(上)中,理解了类是如何从Mach-O加载到内存中,这次我们来解释下分类是如何加载中的,以及分类和类搭配使用的情况

分类的本质

前提:在main中定义LGperson的分类LG

方式一:通过clang

同时,我们发现了一个问题:查看看_prop_list_t,明明分类中定义了属性,但是在底层编译中并没有看到属性,如下图所示,这是因为分类中定义的属性没有相应的set、get方法,我们可以通过关联对象来设置(关于如何设置关联对象,我们将在后续的扩展中进行说明)

方式三:通过objc源码搜索 category_t

总结

综上所述,分类的本质 是一个_category_t类型

分类的加载

前提:创建LGPerson的两个分类:LGA、LGB

在上一篇类的加载(上)文章中的realizeClassWithoutSwift -> methodizeClass -> attachToClass -> load_categories_nolock -> extAlloc ->attachCategories中提及了rwe的加载,其中分析了分类的data数据 时如何 加载到中的,且分类的加载顺序是:LGA -> LGB的顺序加载到类中,即越晚加进来,越在前面

其中查看methodizeClass的源码实现,可以发现类的数据分类的数据是分开处理的,主要是因为在编译阶段,就已经确定好了方法的归属位置(即实例方法存储在中,类方法存储在元类中),而分类是后面才加进来的

其中分类需要通过attatchToClass添加到类,然后才能在外界进行使用,在此过程,我们已经知道了分类加载三步骤的后面两个步骤,分类的加载主要分为3步:

分类的加载时机

下面我们来探索分类数据的加载时机,以主类LGPerson + 分类LGA、LGB 均实现+load方法为例

通过第二步数据准备反推第一步的加载时机

addToClass方法中,这里经过调试发现,从来不会进到if流程中,除非加载两次,一般的类一般只会加载一次

全局搜索load_categories_nolock的调用,有两次调用

通过堆栈信息分析

所以综上所述,该情况下的分类的数据加载时机的反推路径为:attachCategories -> load_categories_nolock -> loadAllCategories -> load_images

而我们的分类加载正常的流程的路径为:realizeClassWithoutSwift -> methodizeClass -> attachToClass ->attachCategories

其中正向和反向的流程如下图所示:

我们再来看一种情况:主类+分类LGA实现+load,分类LGB不实现+load方法

总结只要有一个分类是非懒加载分类,那么所有的分类都会被标记位非懒加载分类,意思就是加载一次 已经开辟了rwe,就不会再次懒加载,重新去处理 LGPerson

分类和类的搭配使用

通过上面的两个例子,我们可以大致将类 和 分类 是否实现+load的情况分为4种

类+分类
分类实现+load 分类未实现+load
类实现+load 非懒加载类+非懒加载分类 非懒加载类+懒加载分类
类未实现+load 懒加载类+非懒加载分类 懒加载类+懒加载分类

非懒加载类 与 非懒加载分类

主类实现了+load方法,分类同样实现了+load方法,在前文分类的加载时机时,我们已经分析过这种情况,所以可以直接得出结论,这种情况下

其调用路径为:

非懒加载类 与 懒加载分类

主类实现了+load方法,分类未实现+load方法

从上面的打印输出可以看出,方法的顺序是 LGB—LGA-LGPerson类,此时分类已经 加载进来了,但是还没有排序,说明在没有进行非懒加载时,通过cls->data读取Mach-O数据时,数据就已经编译进来了,不需要运行时添加进去* 来到methodizeClass方法中断点部分

来到prepareMethodLists的for循环部分

来到fixupMethodList方法中的if (sort) {部分

走到mlist->setFixedUp();,在读取list

通过打印发现,仅对同名方法进行了排序,而分类中的其他方法是不需要排序的,其你imp地址是有序的(从小到大) -- fixupMethodList中的排序只针对 name 地址进行排序

总结非懒加载类 与 懒加载分类的数据加载,有如下结论:

懒加载类 与 懒加载分类

主类和分类均未实现+load方法

总结懒加载类 与 懒加载分类数据加载是在消息第一次调用时记载

懒加载类 与 非懒加载分类

主类未实现+load方法, 分类实现了+load方法

总结懒加载类 + 非懒加载分类的数据加载,只要分类实现了load,会迫使主类提前加载,即 主类 强行转换为 非懒加载类样式

总结

类和分类搭配使用,其数据的加载时机总结如下:

如下图所示

补充:load_images原理分析

load_images方法的主要作用是加载镜像文件,其中最重要的有两个方法:prepare_load_methods(加载) 和 call_load_methods(调用)

进入prepare_load_methods源码

进入call_load_methods源码,主要有3部分操作

综上所述,load_images方法整体调用过程原理图示如下

主要分为两步

上一篇 下一篇

猜你喜欢

热点阅读