iOS 开发 iOS Developer架构师之路

Objective-C 中 +load 与 +initializ

2018-07-21  本文已影响35人  RyanWong_iOS

  在Apple的文档里很清楚的标明 load 方法 与 initialize 方法 的区别在于,load 在类文件被项目引用的时候就会被调用,initialize 在类 或 其子类的第一个方法被调用的时候被调用。所以如果类文件没有被项目引用就不会调用 load 方法,如果项目引用了类文件,但没有调用其方法,就不会调用 initialize 方法。

  我们通过一些案例来证实两者的调用顺序:

1、load

先创建三个类,分别为 FatherClassSonClassSonClass+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、类别会覆盖主类的initializeload则不会被覆盖;
4、load顺序在 initialize之前;

上一篇下一篇

猜你喜欢

热点阅读