+load和+initialize

声明:本文仅供记忆使用,并不适合新手小白观看

+load方法

  • +load方法会在runtime加载类、分类时调用,每个类、分类的+load,在程序运行过程中只调用一次
  • +load方法是根据方法地址直接调用,并不是经过objc_msgSend函数调用
  • 调用顺序
  1. 先调用类的+load
    按照编译先后顺序调用(先编译,先调用)
    调用子类的+load之前会先调用父类的+load
  2. 再调用分类的+load
    按照编译先后顺序调用(先编译,先调用)
  • runtime代码调用
    • objc4源码解读过程:objc-os.mm
      _objc_init
      load_images
      prepare_load_methods
      schedule_class_load
      add_class_to_loadable_list
      add_category_to_loadable_list
      call_load_methods
      call_class_loads
      call_category_loads
      (*load_method)(cls, SEL_load)

+initialize方法

  • +initialize方法会在类第一次接收到消息时调用

  • +initialize和+load的很大区别是,+initialize是通过objc_msgSend进行调用的,所以有以下特点
    如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次)
    如果分类实现了+initialize,就覆盖类本身的+initialize调用

  • 调用顺序

    1. 如果父类没有initialize过,先调用父类的objc_msgSend(+initialize),就相当于走消息机制,如果父类分类实现了+initialize方法会调用分类的+initialize;
    2. 再调用子类的objc_msgSend(initialize),就相当于走消息机制,如果子类分类实现了+initialize方法会调用分类的+initialize;
      具体看伪代码
  • 伪代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    lookUpImpOrForward {
    查询方法操作…
      if (!子类Initialized) {
                if (!父类Initialized) {
                  objc_msgSend(父类,@selector(initialize));
                  父类Initialized = YES;
                }
                objc_msgSend(子类,@selector(initialize));
                子类Initialized = YES;
          }
    }
  • runtime代码调用

    • objc4源码解读过程
      objc-msg-arm64.s
      objc_msgSend
    • objc-runtime-new.mm
      class_getInstanceMethod
      lookUpImpOrNil
      lookUpImpOrForward
      _class_initialize
      callInitialize
      objc_msgSend(cls, SEL_initialize)

参考资料

runtime源码