+load 和 +initialize

Posted dins

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了+load 和 +initialize相关的知识,希望对你有一定的参考价值。

技术图片

APP 启动到执行 main 函数之前,程序就执行了很多代码。

执行顺序:

  1. 将程序依赖的动态链接库加载到内存
  2. 加载可执行文件中的所有符号,代码 runtime 解析被编译的符号代码
  3. 遍历所有的 class
  4. 按继承层级一次调用 Class 的 load 和 category 的 load 方法。

+(void)initialize 与 +(void)load 两个方法的比较

+load +initialize
调用时机 被添加 runtime 时 收到第一条消息时,也可能永远不调用
调用顺序 父类 -> 子类 -> 分类 父类 -> 子类
调用次数 1次 系统执行 1 次,手动可以调用多次
是否需要显式调用父类实现
是否沿用父类的实现
分类中的实现 类和分类都执行 分类覆盖类中的实现

initialize 方法的调用是线程安全的。

load的执行顺序:

  1. 对于有依赖关系的两个库中,被依赖的类的 load 会优先调用。但在一个库之内,调用顺序是不确定的。
  2. 一个类的 load 方法不用写明 [super load],父类就会收到调用,并且在子类之前。也就是执行子类的load方法之前,当父类未加载时会先执行父类的 Load 方法。
  3. 分类 category 的方法在最后执行
  4. 执行完上面的才按 compile sources 的顺序执行 load。
  5. 对于一个类而言,没有 load 方法实现就不会调用,不会考虑对 NSObject 的继承。

initialize 的执行顺序:

  1. initialize 的自然调用是在第一次主动使用当前类的时候。
  2. 在 initialize 方法收到调用时,运行环境基本健全。
  3. initialize 的运行过程中是能保证线程安全的。
  4. 和 load 不同,即使子类不实现 initialize 方法,会把父类的实现继承过来调用一遍。注意的是在此之前,父类的方法已经被执行过一次了,同样不需要 super 调用。

相同点:

  1. 在不考虑开发者主动使用的情况下,系统最多会调用一次
  2. 父类在子类之前被调用。
  3. 都是为了应用运行提前创建合适的运行环境

不同点:

  1. load 方法会在加载类的时候就被调用,也就是 ios 应用启动时就会加载所有的类,就会调用每个类的 +load 方法;initialize 方法会在第一次初始化这个类之 前被调用,我们用它来初始化静态变量。
  2. load会在 main() 函数之前调用,+initialize 则在类实例化或调用类方法时调用。load 顺序在 initialize 之前。
  3. 如果子类中没有 +initialize 方法,则会再次调用父类的 +initialize 方法。
  4. 类别会覆盖主类的 +initialize 方法,+load 方法则不会被覆盖。
  5. +initialize 方法的调用看起来会更合理,通常在它里面写代码比在 + load 里写更好,因为它是懒调用的,是有可能完全不被调用的。
  6. 类接收消息时,运行时会先检查 + initialize 有没有被调用过。如果没有,则会在消息被处理前调用。
  7. initialize 最终是通过 objc_msgSend 来执行的,objc_msgSend 会执行一系列方法查找,并且 Category 的方法会覆盖类中的方法;load 是在被添加到 runtime 时开始执行,父类最先执行,然后是子类,最后是 Category。又因为是直接获取函数指针来执行,不会像 objc_msgSend 一样会有方法查找的过程。

以上是关于+load 和 +initialize的主要内容,如果未能解决你的问题,请参考以下文章

细说OC中的load和initialize方法

NSObject的load和initialize方法

iOS开发-类的加载load函数和initialize函数

load和initialize的区别

iOS Load方法 和 initialize方法的比较

iOS load和initialize的区别