其實有時間還是需要多補充下基礎知識的,畢竟步子跨太大會扯到襠。
- load
Invoked whenever a class or category is added to the Objective-C runtime; implement this method to perform class-specific behavior upon loading.
這是 Apple Doc 上對 - load 的描述。(強行秀一波翻譯,其實我是個英語渣,最好還是看英文吧)當一個類或分類被添加到運行時的時候會觸發這個方法;實現這個方法可以在加載這個類時執行一些特定的操作。
寫下 demo 看看這個方法在繼承樹上是什么執行順序,雖然文檔里有寫。
- A class’s +load method is called after all of its superclasses’ +load methods.
- A category +load method is called after the class’s own +load method.
先執行所有的父類的 - load 方法,分類的 - load 方法將會是最后執行。
// Parent.m
+ (void)load {
NSLog(@"Parent load");
}
// Child.m
+ (void)load {
NSLog(@"Child load");
}
// Child+Category.m
+ (void)load {
NSLog(@"Child Category load");
}
有興趣的朋友可以自己去試試。
- initialize
Initializes the class before it receives its first message.
在收到第一條消息之前初始化類,也就是說你 #import 了這個類,但是沒有用到這個類,就不會初始化它(有點懶加載的味道)。
The runtime sends the initialize message to classes in a thread-safe manner. Superclasses receive this message before their subclasses. The superclass implementation may be called multiple times if subclasses do not implement initialize—the runtime will call the inherited implementation—or if subclasses explicitly call [super initialize].
runtime 會線程安全地發送 initialize 消息給類。父類會比它的子類先收到這個消息。如果子類沒有實現 initialize 這個方法,那么父類的 initialize 方法會被執行多次 —— 否則 runtime 將會調用子類實現 —— 除非子類明確調用 [super initialize] 。
demo time。動手 ba 一 ba 。
// Parent.m
+ (void)initialize {
NSLog(@"Parent initialize");
}
// Child.m
+ (void)initialize {
NSLog(@"Child initialize");
}
// Child+Category.m
+ (void)initialize {
NSLog(@"Child Category initialize");
}
// main.m
int main(int argc, const char * argv[]) {
@autoreleasepool {
[Child new];
[Child new];
}
return 0;
}
結果中可以看出分類中的 initialize 會覆蓋掉類中 initialize 方法,而父類的 initialize 方法仍舊會被執行。
接下來我們把子類中的 initialize 方法注釋掉,重新跑一遍看看結果。
發現父類的 initialize 方法被調用了兩遍,然后我們看文檔中的這段話。
The runtime sends initialize to each class in a program just before the class, or any class that inherits from it, is sent its first message from within the program.
這段話的大致意思就是說 runtime 會發送 initialize 給這個類以及這個類的所有父類,因此當我們使用 Child 的時候,runtime 會先發送 initialize 消息給 Parent ,然后發送給 Child ,但是 Child 沒有實現 initialize 方法,所以就再次執行了 Parent 的 initialize 。
所以如果使用一個 Grandson (沒有實現 initialize),則 Parent 的 initialize 將會被調用三次。
有時候我們可能需要這樣的效果,但是大多數時間我們是不需要這樣的,因此我們可以在實現 initialize 時,這樣寫來避免這個問題。
+ (void)initialize {
if (self == [ClassName self]) {
// ... do the initialization ...
}
}
用處(歡迎補充)
- load
在 load 中實現Method Swizzling:
+ (void)load {
Method a = class_getInstanceMethod([self class], @selector(logA));
Method b = class_getInstanceMethod([self class], @selector(logB));
method_exchangeImplementations(a, b);
}
- (void)logA {
NSLog(@"A");
}
- (void)logB {
NSLog(@"B");
}
- initialize
初始化一些靜態對象
// static NSArray *array = @[@1, @2]; //這樣是不行滴,編譯器不接受,只有數據類型才能這樣哦
static NSArray *array;
+ (void)initialize {
if (self == [Parent class]) {
array = @[@1, @2];
}
}
小結
| | load | initialize |
| :--- : | :-----: | :----: |
| 調用時機 | 類被添加到 runtime 時 | 類第一次接收到消息之前 |
| 調用順序 | 父類->子類->分類 | 父類 -> 子類(分類) |
| 調用次數 | 1次 | 多次 |
| 顯式調用父類 | 否 | 否 |
| 分類中的實現 | 類和分類都執行 | 覆蓋類的實現,執行分類的實現 |
| 線程安全 | 安全 | 安全 |
上表主要就是這兩個方法的特點,因為是線程安全的,所以在這兩個方法盡量少執行復雜的操作,防止阻塞線程。
以上就是我對這兩個方法的描述,如有不對望指正,給個喜歡以示支持。