网上有很多这样的面试题,之前也有人问过我。但是一直也没有时间进行详细的探索,并做记录。
最近正好拿出来进行研究。下面会用到源码objc4-781,在官网上下载最新的。
我们先来看一下+load方法,我们新建几个类和分类,类和分类里面写上+load方法,并做打印
main函数里面什么也不写,头文件也不需要引入,我们运行一下,看一下会有什么效果。
我们可以看到这里已经调用了上面定义的类和分类的+load方法,我们什么都没有做,为什么会调用呢?
我们想要分析为什么,还需要从源码进行分析。
首先我们要找到runtime的入口,入口是在objc-os.mm文件下面的_objc_init方法
_dyld_objc_notify_register里面load_images点进去之后下面有个 call_load_methods()方法点进去
上面是先调用类方法里面的+load方法,下面是调用分类里面的+load方法。从上面的打印结果我们也可以看出是先调用类的在调用分类的。看一下调用方法里面的实现。
loadable_classes是非懒加载类+load 方法的数组。是loadable_class结构体,里面包含Class和IMP两个变量。所以classes里面也是同样的,之后用for循环遍历直接调用load方法。
但是loadable_classes数组里面的东西还有一些细节需要注意。就是里面存储结构体的顺序什么样的。因为顺序不同调用的结果也就不一样。到底在哪里看呢?
上面我们有一个load_images方法,里面有一句prepare_load_methods((const headerType *)mh);代码,点进去
我们可以看到classlist里面放的是所有不是懒加载的类,通过for循环调用schedule_class_load这个方法。
add_class_to_loadable_list这个方法里面就是把有+load的发放入到loadable_classes数组中。但是上面可以看出使用了递归,
是对传入进来类的父类进行遍历。所以加入loadable_classes数组放把父类的+load方法先放到里面。所以在下面调用的时候是先调用父类的+load。
除了继承关系以外,其他的顺序是按照编译的顺序进行调用。
分类原理类似,但是不会像类一样先调用父类的load,分类只是单纯的按照编译顺序进行调用。
这里也可以看出直接就调用添加数组里面。
总结一下+load方法
1、+load方法会在runtime加载类和分类时调用
2、调用的顺序有几个注意点(先调用类的load方法,如果类有继承关系先调用父类的load方法---类才有的,分类没有,其他情况就是按照编译的顺序进行调用,先编译先调用)