load

系统加载load方法大致可以梳理成如下几步:

  1. 准备load方法
    1. 递归获取superclass,获取load方法,加入待加载class load方法表(所以父类的load在最前)
    2. 按照category编译顺序加载category中的load方法,加入到另一个待加载category load方法表
  2. 从头到尾取出class load方法表,获取imp,直接执行(获取的是函数指针imp,所以不走msg_send)
  3. 再取category load方法表,执行。

所以,可以看出,load方法的执行顺序是 父类 -> 子类 -> category,同时是直接执行imp,不走msg_send,所以也不会执行查找函数方法表的流程,父类子类跟category之间是独立的

initialize

跟load不同,initialize的调用时机是第一次使用该类。
调用顺序上跟load类似,也是递归父类,但之后是直接调用msg_send(selector)。因为走得是msg_send,所以会查找方法表,所以category会覆盖类的initialize;同时,如果当前类没有实现initialize方法,也会因为查找方法表调用到父类的方法,所以父类initialize方法可能被调用多次。

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

参考:

  1. hi_xgb | Objective-C 深入理解 +load 和 +initialize