在Apple的文档里很清楚的标明 load
方法 与 initialize
方法 的区别在于,load
在类文件被项目引用的时候就会被调用,initialize
在类 或 其子类的第一个方法被调用的时候被调用。所以如果类文件没有被项目引用就不会调用 load
方法,如果项目引用了类文件,但没有调用其方法,就不会调用 initialize
方法。
我们通过一些案例来证实两者的调用顺序:
1、load
先创建三个类,分别为 FatherClass
、SonClass
、SonClass+load
,在各自的类中加入load方法:
//In FatherClass
@implementation FatherClass
+ (void)load {
NSLog(@"%s", __func__);
}
//In SonClass,继承 FatherClass
@implementation SonClass
+ (void)load {
NSLog(@"%s", __func__);
}
// In SonClass+load.m,SonClass类的分类
@implementation SonClass(load)
+ (void)load {
NSLog(@"%s", __func__);
}
输出
2018-07-21 09:40:43.618180+0800 LearningiOS[2725:164743] +[FatherClass load]
2018-07-21 09:40:43.619005+0800 LearningiOS[2725:164743] +[SonClass load]
2018-07-21 09:40:43.619356+0800 LearningiOS[2725:164743] +[SonClass(load) load]
可以发现父类的load
是最先调用,然后到子类自身的load
被调用,而子类类别的load
是最后调用的。并且每个类的load
只会调用一次。
2、initialize
在前面创建的三个类中加入 initialize 方法:
//In FatherClass
@implementation FatherClass
+ (void)initialize {
NSLog(@"%s", __func__);
}
//In SonClass,继承 FatherClass
@implementation SonClass
+ (void)initialize {
NSLog(@"%s", __func__);
}
// In SonClass+load.m,SonClass类的分类
@implementation SonClass(load)
+ (void)initialize {
NSLog(@"%s", __func__);
}
输出
1、无实例、无调用类方法
无打印
2、加入 SonClass *son = [[SonClass alloc] init]; 或 [SonClass function];
2018-07-21 10:49:32.068987+0800 LearningiOS[3907:239033] +[FatherClass initialize]
2018-07-21 10:49:32.069138+0800 LearningiOS[3907:239033] +[SonClass(load) initialize]
3、删掉SonClass+load 类,加入 2
2018-07-21 10:54:45.145654+0800 LearningiOS[4028:246341] +[FatherClass initialize]
2018-07-21 10:54:45.145773+0800 LearningiOS[4028:246341] +[SonClass initialize]
4、删掉SonClass 中的 initialize 方法,加入 2
2018-07-21 10:59:41.384934+0800 LearningiOS[4114:253215] +[FatherClass initialize]
2018-07-21 10:59:41.385123+0800 LearningiOS[4114:253215] +[FatherClass initialize]
由打印可以看出,
1、当类没有被实例或者类方法没有被调用的时候,不会执行 initialize
方法;
2、当存在子类类别的情况下,实例化子类或者调用子类 类方法,系统自动调用 其父类和类别的initialize
方法,不调用子类中的initialize
方法;
3、优先调用父类的initialize
方法;
4、当子类没有实现initialize
方法的时候,会重复调用其父类的initialize
方法。
假如类在SecondViewController中实例化,第一次push至SecondViewController会执行一次该类会调用一次initialize
方法,其后返回再push至SecondViewController,则无新的打印。证明每个类的initialize
方法系统也只调用一次。
3、两者结合
把load 和 initialize 一起打印
2018-07-21 11:20:29.224008+0800 LearningiOS[4425:276418] +[FatherClass load]
2018-07-21 11:20:29.225736+0800 LearningiOS[4425:276418] +[SonClass load]
2018-07-21 11:20:29.505386+0800 LearningiOS[4425:276418] +[FatherClass initialize]
2018-07-21 11:20:29.505556+0800 LearningiOS[4425:276418] +[SonClass initialize]
可以看出 load
方法顺序在 initialize
之前。
4、使用场景
1、load
通常用于Method Swizzle
;
2、initialize
可以用于初始化全局变量或静态变量;
结论
相同点:
1、系统都只执行一次;
2、假如父类 和 子类 都被调用,父类在子类之前被调用;
不同点:
1、load
在文件被项目引用的时候就被调用,在main
函数之前,initialize
则在类实例化 或 类方法被调用时调用;
2、子类中没有load
方法的情况下,系统不会多次调用父类的load
方法,如果子类中没有initialize
方法,则会再次调用父类的initialize
方法;
3、类别会覆盖主类的initialize
,load
则不会被覆盖;
4、load
顺序在 initialize
之前;