+load()
,+initialize()
,-init()
方法应该并不陌生,可是,对于这些方法的调用逻辑和顺序,可能会偶有疑惑,本文经过 demo 的方式,来探究一下这几个方法+load()
方法是当类或分类被添加到 Objective-C runtime
时被调用的,实现这个方法可让咱们在类加载的时候执行一些类相关的行为,子类的 +load
方法会在它的全部父类的 +load()
方法以后执行,而分类的 +load()
方法会在它的主类的 +load()
方法以后执行。可是不一样的类之间的 +load()
方法的调用顺序是不肯定的 安全
TestClass
类,而后在建立一个继承自该类的子类
TestClassSubClass
,和两个
TestClass
的分类
TestClass+Z
,
TestClass+Y
,分别在这几个类中实现
+load()
方法,并打印输出,而后在
main()
中也写一个输出语句,运行程序,咱们来看一下输出
int main(int argc, char * argv[]) {
@autoreleasepool {
NSLog(@" %s", __func__);
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
复制代码
如咱们所看到的,+load()
的调用是在 main()
函数以前,而且在整个 APP 运行过程当中只会被调用一次,对 +load()
方法进行调用,是直接使用函数内存地址的方式 (load_method)(cls, SEL_load);
而不是使用发送消息 objc_msgSend
的方式,父类 TestClass
的 +load()
方法最早被调用,然后是子类和分类,对于多个分类的 +load()
的调用顺序的前后,取决于编译顺序,测试一下,咱们在 Bulid Phases->Compile Sources
调整分类的编译顺序 bash
TestClass+Z
的
+load()
方法先于
TestClass+Y
被调用
+load()
方法的调用是在 main()
函数以前,而且不须要主动调用,程序启动会把全部的文件加载,文件若是重写了 +load()
方法,主类、子类、分类都会加载调用 +load()
方法;+load()
是在 main()
函数以前调用,因此在这个方法里面不要做耗时操做或者阻塞的操做,会影响启动速度;main()
函数以前自动调用,+load()
方法调用的时候使用者根本就不能肯定本身要使用的对象是否已经加载进来了,因此千万不能在这里初始化对象;+load()
方法中进行 Method Swizzle
操做,交换方法。+initialize()
方法是在类或它的子类收到第一条消息以前被调用的,这里所指的消息包括实例方法和类方法的调用,也就是说 +initialize()
方法是以懒加载的方式被调用的,若是程序一直没有给某个类或它的子类发送消息,那么这个类的 +initialize()
方法是永远不会被调用的,关于调用,咱们一样用代码进行测试函数
TestClass
实现 + initialize()
方法,子类和分类中不实现,分别以下调用TestClass *class1 = [[TestClass alloc] init];
TestClass *class2 = [[TestClass alloc] init];
// TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
// TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
// TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
// TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
// TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
复制代码
TestClass *class1 = [[TestClass alloc] init];
TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
复制代码
// TestClass *class1 = [[TestClass alloc] init];
// TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
复制代码
会发现,无论咱们建立 TestClass
几个对象,[TestClass initialize]
只被调用一次,而若是建立了 TestClassSubClass
对象,不管是否建立 TestClass
对象,[TestClass initialize]
都会调用两次,可见当子类未实现 +initialize()
方法,会调用父类 +initialize()
方法。测试
TestClass
和子类中分别实现 + initialize
方法TestClass *class1 = [[TestClass alloc] init];
TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
复制代码
// TestClass *class1 = [[TestClass alloc] init];
// TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
复制代码
+ initialize()
方法,初始化都会至少去调用一次父类的
+ initialize()
方法,而若是自身实现了
+ initialize()
方法,那么继续调用本身的
+ initialize()
方法,若是未实现,则去调用父类的
+ initialize()
方法
TestClass
和子类、分类中分别实现 + initialize()
方法TestClass *class1 = [[TestClass alloc] init];
TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
复制代码
// TestClass *class1 = [[TestClass alloc] init];
// TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
复制代码
+ initialize()
方法,变成了调用
TestClass+Y
的
+ initialize()
方法,这是由于最后被编译的
TestClass+Y
中的
+ initialize()
方法覆盖了主类的
+ initialize()
方法
+ initialize()
方法会比子类先执行;+ initialize()
方法时,会调用父类 + initialize()
方法,子类实现 + initialize()
方法时,会覆盖父类 + initialize()
方法;Category
都实现了 + initialize()
方法,会覆盖类中的方法,只执行一个(会执行Compile Sources
列表中最后一个 Category
的 + initialize()
方法)。TestClass
和子类分别实现 -init()
方法TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
复制代码
-init()
方法,而后调用自身的
-init()
方法,而且每次初始化时都会调用
只在 TestClass
实现 -init()
方法ui
调用结果以下 spa
-init()
方法时,每初始化一个对象,只会调用一次父类的 -init()
方法 +load()
和 +initialize()
都会在实例化对象以前调用,前者是在 main()
函数以前,后者是在 main()
函数以后;+load()
和 +initialize()
方法都不会显式的调用父类的方法而是自动调用,即便子类没有 +initialize()
方法也会调用父类的方法,+load()
方法不会调用父类;+load()
和 +initialize()
方法内部使用了锁,所以他们是线程安全的,实现时要尽量简单,避免线程阻塞,不要再次使用锁;+load()
方法经常使用来 method swizzle
,+initialize()
经常用于初始化全局变量和静态变量。