+load 和 +initialize
Posted dins
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了+load 和 +initialize相关的知识,希望对你有一定的参考价值。
APP 启动到执行 main 函数之前,程序就执行了很多代码。
执行顺序:
- 将程序依赖的动态链接库加载到内存
- 加载可执行文件中的所有符号,代码 runtime 解析被编译的符号代码
- 遍历所有的 class
- 按继承层级一次调用 Class 的 load 和 category 的 load 方法。
+(void)initialize 与 +(void)load 两个方法的比较
+load | +initialize | |
---|---|---|
调用时机 | 被添加 runtime 时 | 收到第一条消息时,也可能永远不调用 |
调用顺序 | 父类 -> 子类 -> 分类 | 父类 -> 子类 |
调用次数 | 1次 | 系统执行 1 次,手动可以调用多次 |
是否需要显式调用父类实现 | 否 | 否 |
是否沿用父类的实现 | 否 | 是 |
分类中的实现 | 类和分类都执行 | 分类覆盖类中的实现 |
initialize 方法的调用是线程安全的。
load的执行顺序:
- 对于有依赖关系的两个库中,被依赖的类的 load 会优先调用。但在一个库之内,调用顺序是不确定的。
- 一个类的 load 方法不用写明 [super load],父类就会收到调用,并且在子类之前。也就是执行子类的load方法之前,当父类未加载时会先执行父类的 Load 方法。
- 分类 category 的方法在最后执行
- 执行完上面的才按 compile sources 的顺序执行 load。
- 对于一个类而言,没有 load 方法实现就不会调用,不会考虑对 NSObject 的继承。
initialize 的执行顺序:
- initialize 的自然调用是在
第一次主动使用
当前类的时候。 - 在 initialize 方法收到调用时,运行环境基本健全。
- initialize 的运行过程中是能保证线程安全的。
- 和 load 不同,即使子类不实现 initialize 方法,会把父类的实现继承过来调用一遍。注意的是在此之前,父类的方法已经被执行过一次了,同样不需要 super 调用。
相同点:
- 在不考虑开发者主动使用的情况下,系统最多会调用一次
- 父类在子类之前被调用。
- 都是为了应用运行提前创建合适的运行环境
不同点:
- load 方法会在加载类的时候就被调用,也就是 ios 应用启动时就会加载所有的类,就会调用每个类的 +load 方法;initialize 方法会在第一次初始化这个类之 前被调用,我们用它来初始化静态变量。
- load会在 main() 函数之前调用,+initialize 则在类实例化或调用类方法时调用。load 顺序在 initialize 之前。
- 如果子类中没有 +initialize 方法,则会再次调用父类的 +initialize 方法。
- 类别会覆盖主类的 +initialize 方法,+load 方法则不会被覆盖。
- +initialize 方法的调用看起来会更合理,通常在它里面写代码比在 + load 里写更好,因为它是懒调用的,是有可能完全不被调用的。
- 类接收消息时,运行时会先检查 + initialize 有没有被调用过。如果没有,则会在消息被处理前调用。
- initialize 最终是通过 objc_msgSend 来执行的,objc_msgSend 会执行一系列方法查找,并且 Category 的方法会覆盖类中的方法;load 是在被添加到 runtime 时开始执行,父类最先执行,然后是子类,最后是 Category。又因为是直接获取函数指针来执行,不会像 objc_msgSend 一样会有方法查找的过程。
以上是关于+load 和 +initialize的主要内容,如果未能解决你的问题,请参考以下文章