load 和 initialize 方法的执行顺序以及类和对象的关系

470 查看

先了解一下应用启动之后,做了什么。
main.m 中的 main() 是程序的入口,但在进入 main 函数之前,程序就执行了很多代码(不然也不会启动那么久)。
启动后执行顺序:

将程序依赖的动态链接库加载进内存
加载可执行文件中的所有符号、代码
runtime 解析被编译过的符号代码,遍历所有 Class,按继承层级依次调用Class 的 load 方法和其 Category 的 load 方法。

load 方法的执行顺序

首先来做点测试,来看看 load 方法的执行顺序。
先建一个 Single View Application。展开 Build Phases 的 Compile Sources,如下图:

1111400498-545b91c7b90efe48

在每个类的 @implementation 里加上

来看看每个类的 load 方法的调用顺序(main.m 我做了特殊处理)。以下是运行结果:

顺序和 Compile Sources 顺序一致,目前来看,Compile Sources 的顺序就是 load 方法的调用顺序。

再来一个测试,依次添加 ClassFather,以及它的子类 ClssSon,以及另一个 ClassA。结果 Compile Sources 的顺序和我想象中的不一样,如下图

2221400498-b512e90e27bd4be8

看起来毫无规律啊。(这是一个问题,先记录一下)

这个时候我改变顺序,将 ClassSon 移动到最前面,ClassFather 移动到最后面。如图

3331400498-356f7c6eb1f685dc

下面是运行结果:

也就是本应先执行 ClassSon load 方法,但先执行了 ClassFather load 方法,再来一次测试。
我将 ClassSon 里的 load 方法注释掉,以下是运行结果:

也就是说,只有在你重写了 load 方法的时候,会在执行你的 load 之前,当父类未加载时,先执行父类的 load 方法。

再来一个分类的情况,分类就很有意思了。先添加了 ClssSon+category,ClssSon+category2,ClassFather+category。将它们移动至最上方。如图

4441400498-6e09da5049903c69

运行结果

明明应该最早执行 load 方法的分类,却统统最后执行,甚至晚于和它没有啥关系的 ClassMain load。所以分类低人一等,最晚执行 load 方法。

得出结论,load 的执行顺序满足以下几条

  • 执行子类的 load 之前,当父类未加载时,先执行父类的 load 方法。
  • 分类的 load 方法统一在最后执行
  • 优先满足以上两条,再满足按 Compile Sources 的顺序执行 load 方法。

initialize 方法的执行顺序

这个时候来测试 initialize 的执行顺序,在 ClassFather ClassSon 以及他们的分类都重写 initialize 方法,并将 ClassFather 移动至 ClassSon 的前面,在 ClassFather load 里添加调用 ClassSon 的类方法的代码,如下

运行结果如下

从运行结果来看,先执行了 ClassFather(category) initialize,再执行了 ClassSon(category) initialize,而 ClassSon load 在后面执行。
也就是说 load 方法还未执行也不会影响到这个类的使用。
另一个现象是执行子类 initialize 的时候会先执行其父类的 initialize。且 category 的覆写效应对 load 方法无效,但对 initialize 方法有效。且按 Complile Sources 的顺序,ClassSon(category2) 先覆写了 ClassSon 的 initialize 方法,接着 ClassSon(category) 覆写了 ClassSon(category2) 的 initialize。

如果将子类以及类别的 initialize 注释掉,再修改 ClassFather(category) initialize ,如下

结果如下

也就是子类会继承父类的 initialize 。当执行完父类的 initialize 方法,准备执行子类的 initialize 方法时,会根据继承链找到父类的 initialize 执行。为了防止重复执行 initialize 里的代码,可以根据调用者来决定是否执行 initialize 里的其它代码。

类和对象

这块写了一部分,但查资料的时候查到写的非常不错的,我觉得我没有写的必要了,留下链接,强烈建议想对 iOS 开发中的类和对象有更深了解的人看看。

从 NSObject 的初始化了解 isa
深入解析 ObjC 中方法的结构

参考资料

iOS程序main函数之前发生了什么