一、 +(void)initialize
001 在接收到第一个消息之前初始化该类。
个人理解是该类内部发出第一条消息之前就会调用,那么第一条消息理解呢?alloc方法调用。
002 运行时initialize以线程安全的方式将消息发送给该类,提到线程安全 就会想到锁的作用,因为以线程安全方式发送消息,那么其他任何尝试给类发送消息的线程都会被阻塞,直到initialize执行完毕。
003 如果子类不实现initialize,则任何超类可以实现多次调用(运行时将调用继承的实现),或者子类显式调用[super initialize]
。如果要保护自己免于多次运行,可以在
initialize 做一个过滤操作:
+ (void)initialize { if (self == [ClassName self]) { // ... do the initialization ... }}
004 initialize 方法限制为尽可能少的必要工作。因为在initialize方法中使用繁重的代码很有可能导致死锁。
例如在initialize方法中初始化静态变量
SDImageAWebPCoder类中
// These constants are available from iOS 14+ and Xcode 12. This raw value is used for toolchain and firmware compatibility
static NSString * kSDCGImagePropertyWebPDictionary = @"{WebP}";
static NSString * kSDCGImagePropertyWebPLoopCount = @"LoopCount";
static NSString * kSDCGImagePropertyWebPDelayTime = @"DelayTime";
static NSString * kSDCGImagePropertyWebPUnclampedDelayTime = @"UnclampedDelayTime";
@implementation SDImageAWebPCoder
+ (void)initialize {
#if __IPHONE_14_0 || __TVOS_14_0 || __MAC_11_0 || __WATCHOS_7_0
// Xcode 12
if (@available(iOS 14, tvOS 14, macOS 11, watchOS 7, *)) {
// Use SDK instead of raw value
kSDCGImagePropertyWebPDictionary = (__bridge NSString *)kCGImagePropertyWebPDictionary;
kSDCGImagePropertyWebPLoopCount = (__bridge NSString *)kCGImagePropertyWebPLoopCount;
kSDCGImagePropertyWebPDelayTime = (__bridge NSString *)kCGImagePropertyWebPDelayTime;
kSDCGImagePropertyWebPUnclampedDelayTime = (__bridge NSString *)kCGImagePropertyWebPUnclampedDelayTime;
}
#endif
}
例如在initialize方法中初始化监听某些通知
SDWebImageDownloader类中
+ (void)initialize {
// Bind SDNetworkActivityIndicator if available (download it here: http://github.com/rs/SDNetworkActivityIndicator )
// To use it, just add #import "SDNetworkActivityIndicator.h" in addition to the SDWebImage import
if (NSClassFromString(@"SDNetworkActivityIndicator")) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
id activityIndicator = [NSClassFromString(@"SDNetworkActivityIndicator") performSelector:NSSelectorFromString(@"sharedActivityIndicator")];
#pragma clang diagnostic pop
// Remove observer in case it was previously added.
[[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStartNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:activityIndicator name:SDWebImageDownloadStopNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:activityIndicator
selector:NSSelectorFromString(@"startActivity")
name:SDWebImageDownloadStartNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:activityIndicator
selector:NSSelectorFromString(@"stopActivity")
name:SDWebImageDownloadStopNotification object:nil];
}
}
005 initialize 每个类仅被调用一次
二 +(void)load
001 任何时候一个类或者分类被添加到runtime中就会被调用,实现这些类中专门的一些方法
002 initialization 执行步骤如下
1.所有初始化在任何你链接的库里
2. 所有load方法 在你的镜像中
3.所有C++初始化以及C++构造函数也在你的镜像中
4.所有初始化的库都链接到你
额外还有
一个类的的+load的方法在所有超类+load执行之后调用。
一个分类的+load的方法在类自身的+load执行之后调用。
在分类中可以实现方法混淆,如果多个分类中实现相同分类方法,调用依据来自于编译顺序
Person---->Student
Person---->Teacher
Person类中实现initialize
+(void)initialize{
NSLog(@"Person initialize");
}
Student类中实现
+(void)initialize{
NSLog(@"Student initialize");
}
- (void)viewDidLoad {
[super viewDidLoad];
Student *aSt = [[Student alloc] init];
Teacher *aTcher = [[Teacher alloc] init];
}
先在父类Person 调用initialize 然后在Student中调用,Teacher 没有实现initialize只能父类Person 调用initialize
initialize 可以被多次调用
load先调用再调用initialize
2020-10-24 11:21:30.554789+0800 LearnLoadInitial[20451:1538690] Person load
2020-10-24 11:21:30.555318+0800 LearnLoadInitial[20451:1538690] Person+cat load
2020-10-24 11:21:30.601336+0800 LearnLoadInitial[20451:1538690] Person initialize
2020-10-24 11:21:30.601453+0800 LearnLoadInitial[20451:1538690] Person+cat personFun
参考文献:
https://developer.apple.com/documentation/objectivec/nsobject/1418815-load?language=objc