原文出處 http://www.jianshu.com/p/d25f691f0b07 該文對原文做了一些整理,此處尊重版權,感謝bestswifter爲我們寫出這麼好的文章
+(void)load 方法只要類所在文件被引用就會被調用,而+(void)initialize是在類或者子類的第一個方法被調用前調用。所以如何類沒有被引用到Complie Sources中就不會調用load方法,因此,load方法是在main函數之前調用的,因此,load方法總是在main函數之前調用的。
Load
如果一個可以調用Load方法,那麼他在調用這個方法前會調用父類的load方法。而且這個方法的實現不需要我們手動干預
// In Parent.m
+ (void)load {
NSLog(@"Load Class Parent");
}
// In Child.m,繼承自Parent
+ (void)load {
NSLog(@"Load Class Child");
}
// In Child+load.m,Child類的分類
+ (void)load {
NSLog(@"Load Class Child+load");
}
// 運行結果:
/*
2016-02-01 21:28:14.379 load[11789:1435378] Load Class Parent
2016-02-01 21:28:14.380 load[11789:1435378] Load Class Child
2016-02-01 22:28:14.381 load[11789:1435378] Load Class Child+load
*/
一般不會在此時寫相關的操作,因爲如果在load方法中實現一些操作的時候,系統還屬於脆弱時期,,如果調用別的類的方法,且該方法依賴於那個類的load方法進行初始化設置,那麼必須確保那個類的load方法已經調用過了,比如
// In Child.m
+ (void)load {
NSLog(@"Load Class Child");
Other *other = [Other new];
[other originalFunc];
// 如果不先調用other的load,下面這行代碼就無效,打印出null
[Other printName];
}
load
方法的調用順序其實有跡可循,我們看到demo的項目設置如下:
load
方法中實現Method
Swizzle:// In Other.m
+ (void)load {
Method originalFunc = class_getInstanceMethod([self class], @selector(originalFunc));
Method swizzledFunc = class_getInstanceMethod([self class], @selector(swizzledFunc));
method_exchangeImplementations(originalFunc, swizzledFunc);
}
在Child類中的Load方法中,由於還沒有調用Other的load方法,所以輸出結果是"Original OutPut",而在main函數中就變成了"Swizzled OutPut",這樣就實現了方法替換// In Parent.m
+ (void)initialize {
NSLog(@"Initialize Parent, caller Class %@", [self class]);
}
// In Child.m
// 註釋掉initialize方法
// In main.m
Child *child = [Child new];
2016-02-01 22:57:02.985 load[12772:1509345] Initialize Parent, caller Class Parent
2016-02-01 22:57:02.985 load[12772:1509345] Initialize Parent, caller Class Child
這是因爲在創建子類對象時,首先要創建父類對象,所以會調用一次父類的initilalize方法,然後創建子類時,儘管自己沒有實現initialize方法,但是還是會調用父類的方法。// In Parent.m
+ (void)initialize {
if (self == [Parent class]) {
NSLog(@"Initialize Parent, caller Class %@", [self class]);
}
}
加上判斷後,就不會因爲子類而調用到自己的Initialize方法了