一、+ (void)load
对于每一个 Class 和 Category 来说,必定会调用此方法,而且仅调用一次。当包含 Class 和 Category 的程序库载入系统时,就会执行此方法,并且此过程通常是在程序启动的时候执行。
load 方法会在加载类的时候就被调用,也就是 iOS 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法,在main函数之前调用。
+ load 方法的执行顺序为:类,子类,分类
如果你在一个可加载的 bundle 中实现了 + load,那么它会在 bundle 加载的过程中被调用。
由于调用有着 non-lazy 属性,并且在运行期只调用一次,于是我们可以使用 load 独有的特性和调用时机来尝试 Method Swizzling。当然因为 load 调用时机过早,并且当多个 Class 没有关联(继承与派生),我们无法知道 Class 中 load 方法的优先调用关系,所以一般不会在 load 方法中引入其他的类,这是在开发当中需要注意的。
由于load方法在main函数前被调用,所以在load方法中尽量避免费时的操作,因为这些操作都将导致程序启动时间的延长。
runtime中call_load_methods里是通过load方法的地址直接调用的load方法,而不是通过消息机制来调用的。这就是为什么分类中的load方法并不会覆盖主类以及其他同主类的分类里的load 方法实现的原因
二、+ (void) initialize
+ initialize 方法:苹果官方对这个方法有这样的一段描述:这个方法会在 第一次初始化这个类之前 被调用,我们用它来初始化静态变量。
+ initialize 方法类似一个懒加载,如果没有使用这个类,那么系统默认不会去调用这个方法,且默认只加载一次;
+ initialize 的调用发生在 +init 方法之前。
创建子类时,会去调用父类的initialize方法。意思是当子类没有实现+initialize或者子类在+initialize中显式的调用了[super initialize],那么父类的+initialize方法会被调用多次。
initialize方法的调用看起来会更合理,通常在它里面写代码比在+ load里写更好。+ initialize很有趣,因为它是懒调用的,也有可能完全不被调用。类第一次被加载时,initialize不会被调用。类接收消息时,运行时会先检查+ initialize有没有被调用过。如果没有,会在消息被处理前调用。
initialize的调用,是该类对象通过isa指针找到元类对象,在元类已缓存的方法列表中查方法,如果有就调用;如果没有就查找方法列表,如果还没有找到,那么就去类的父类的元类对象中查找,找到就调用。如果没有就递归下去直到NSObject的元类对象。
所以举个例子:A,A的子类B, B的分类 B+1,他们都分别实现了initialize方法
当执行 [B alloc]时,执行的顺序是 A,B+1,因为分类的initialize方法覆盖了B的initialize方法。这里考察到了runtime的一些知识。
结论
ObjC 提供了两种自动运行类初始化代码的方法。+load 方法保证了会在 class 被加载的时候调用,这个时机很早,所以对于需要很早被执行的代码来说是很有用的。但是不要滥用。
由于 +initialize 方法是 lazy 触发的,所以对于初始化设置的环境就要友好得多。只要不是在类接收第一条消息之前一定要做的事情,都可以在这个方法里面做。