一、initialize
1、在程序中向一个类或者它的子类第一次发消息的之前,runtime会向该类发送initialize消息。
2、父类在其子类之前接收initialize消息。如果superclass之前没有收到过initialize消息,会首先调用super class的initialize,然后才当前class的initialize。
3、如果子类没有实现initialize方法,或者子类显式调用[super initialize],superclass的实现会被多次调用。
4、runtime以线程安全的方式将initialize消息发送给类。也就是说,initialize由第一个线程运行,以向类发送消息,并且任何试图向该类发送消息的线程都将阻塞,直到initialize完成。
5、如果您希望保护自己不被多次运行,您可以按照以下的方式来构造您的方法:
+ (void)initialize {
if (self == [ClassName self]) {
// ... do the initialization ...
}
}
6、因为initialize是以阻塞的方式被调用,所以在initialize方法中不适宜做过于繁重的初始化工作。特别注意,如果加锁的代码在其他类的initialize方法中调用有可能会导致死锁。因此,不应该依赖于initialize来进行复杂的初始化,而应该完成一些简单的本地初始化。
7、initialize在每个类中只调用一次,如果在category中重写了initialize方法,会覆盖当前类的initialize方法。如果您想为类和类别执行独立的初始化,您应该实现+load方法。
二、load
在类或类别添加到runtime时调用;在这个方法中可以执行一些特定的行为。比如初始化一个全局的表,并将类注册到其中。
#不像initialize,不存在重复调用的情况。
+ (void)load;
初始化过程:
所有链接的framework的initializer
↓
所有+load方法
↓
本程序的所有C++static initializer 和C/C++ attribute(constructor)方法
↓
所有链接本程序的framework的initializer
【注】
当所有super class的load方法调用完成,才执行当前类的load方法
当前class的load方法调用完成,才执行当前category的load方法
三、示例
1、
#本文中用到的示例,大家可以分别注释子类或是父类的initialize或是load方法,运行看看有什么不同#
#Father:父类
#import
@interface Father : NSObject
@end
#import "Father.h"
@implementation Father
+ (void)initialize{
NSLog(@"%s",__func__);
}
+ (void)load{
NSLog(@"%s",__func__);
}
@end
#Son1:继承Father的子类
#import "Father.h"
@interface Son1 : Father
@end
#import "Son1.h"
@implementation Son1
+ (void)initialize{
NSLog(@"%s",__func__);
}
+ (void)load{
NSLog(@"%s",__func__);
}
@end
#Son2:继承Father的子类
#import "Father.h"
@interface Son2 : Father
@end
#import "Son2.h"
@implementation Son2
+ (void)initialize{
NSLog(@"%s",__func__);
}
+ (void)load{
NSLog(@"%s",__func__);
}
@end
#Son1+Load: Son1的分类
#import "Son1.h"
@interface Son1 (Load)
@end
#import "Son1+Load.h"
@implementation Son1 (Load)
+ (void)initialize{
NSLog(@"%s",__func__);
}
+ (void)load{
NSLog(@"%s",__func__);
}
@end
我们只是创建了几个类,什么都不做,运行一下
2018-02-26 12:54:23.054726+0800 runtimeDemo[31256:5838555] +[Father load]
2018-02-26 12:54:23.055196+0800 runtimeDemo[31256:5838555] +[Son1 load]
2018-02-26 12:54:23.055801+0800 runtimeDemo[31256:5838555] +[Son2 load]
2018-02-26 12:54:23.055879+0800 runtimeDemo[31256:5838555] +[Son1(Load) load]
2、若子类没有实现initialize
#import "Son2.h"
@implementation Son2
//+ (void)initialize{
// NSLog(@"%s",__func__);
//}
+ (void)load{
NSLog(@"%s",__func__);
}
@end
#import "ViewController.h"
#import "Son2.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[Son2 new];
}
控制台
2018-02-26 13:30:13.318882+0800 runtimeDemo[31794:5867109] +[Father load]
2018-02-26 13:30:13.319541+0800 runtimeDemo[31794:5867109] +[Son1 load]
2018-02-26 13:30:13.319988+0800 runtimeDemo[31794:5867109] +[Son2 load]
2018-02-26 13:30:13.320241+0800 runtimeDemo[31794:5867109] +[Son1(Load) load]
2018-02-26 13:30:13.992162+0800 runtimeDemo[31794:5867109] +[Father initialize]
2018-02-26 13:30:13.992247+0800 runtimeDemo[31794:5867109] +[Father initialize]
3、+load 执行时机
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[Father new];
[Son1 new];
[Son2 new];
}
@end
控制台
2018-02-26 13:37:48.911794+0800 runtimeDemo[32019:5876718] +[Father load]
2018-02-26 13:37:48.912212+0800 runtimeDemo[32019:5876718] +[Son1 load]
2018-02-26 13:37:48.912451+0800 runtimeDemo[32019:5876718] +[Son2 load]
2018-02-26 13:37:48.912835+0800 runtimeDemo[32019:5876718] +[Son1(Load) load]
2018-02-26 13:37:48.912950+0800 runtimeDemo[32019:5876718] main
2018-02-26 13:37:49.892705+0800 runtimeDemo[32019:5876718] -[AppDelegate application:didFinishLaunchingWithOptions:]
2018-02-26 13:37:49.894483+0800 runtimeDemo[32019:5876718] +[Father initialize]
2018-02-26 13:37:49.894563+0800 runtimeDemo[32019:5876718] +[Son1(Load) initialize]
2018-02-26 13:37:49.894652+0800 runtimeDemo[32019:5876718] +[Son2 initialize]
【总结】
1、+load 类加载到runtime就会调用,按照父类,子类,分类的顺序进行加载。
2、若有多个子类,加载顺序依照building setting中compile sources 中的子类顺序进行加载
3、若父类子类均有分类,加载顺序依照building setting中compile sources 中的分类先后顺序进行加载。
加载顺序
2018-02-26 13:44:34.522342+0800 runtimeDemo[32225:5885402] +[Father load]
2018-02-26 13:44:34.523200+0800 runtimeDemo[32225:5885402] +[Son2 load]
2018-02-26 13:44:34.523312+0800 runtimeDemo[32225:5885402] +[Son1 load]
2018-02-26 13:44:34.523576+0800 runtimeDemo[32225:5885402] +[Son2(Load) load]
2018-02-26 13:44:34.523720+0800 runtimeDemo[32225:5885402] +[Son1(Load) load]
2018-02-26 13:44:34.523912+0800 runtimeDemo[32225:5885402] +[Father(Load) load]
2018-02-26 13:44:34.524117+0800 runtimeDemo[32225:5885402] main
2018-02-26 13:44:35.516505+0800 runtimeDemo[32225:5885402] -[AppDelegate application:didFinishLaunchingWithOptions:]
4、initialize只有在用到类的时候才会被调用。
5、父类initialize可能会被调用多次。
四、应用场景
1、+load方法中完成swizzing method。
2、统跳协议模式的模块化工程,每个类在+load方法中注册当前类可以相应的链接。
3、等等
以上,掌握这两个方法在程序加载的时候做一些初始化的工作。
如果有不准确的地方,欢迎批评指正。