+load()
,+initialize()
,-init()
方法應該並不陌生,可是,對於這些方法的調用邏輯和順序,可能會偶有疑惑,本文經過 demo 的方式,來探究一下這幾個方法+load()
方法是當類或分類被添加到 Objective-C runtime
時被調用的,實現這個方法可讓咱們在類加載的時候執行一些類相關的行爲,子類的 +load
方法會在它的全部父類的 +load()
方法以後執行,而分類的 +load()
方法會在它的主類的 +load()
方法以後執行。可是不一樣的類之間的 +load()
方法的調用順序是不肯定的 安全
TestClass
類,而後在建立一個繼承自該類的子類
TestClassSubClass
,和兩個
TestClass
的分類
TestClass+Z
,
TestClass+Y
,分別在這幾個類中實現
+load()
方法,並打印輸出,而後在
main()
中也寫一個輸出語句,運行程序,咱們來看一下輸出
int main(int argc, char * argv[]) {
@autoreleasepool {
NSLog(@" %s", __func__);
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
複製代碼
如咱們所看到的,+load()
的調用是在 main()
函數以前,而且在整個 APP 運行過程當中只會被調用一次,對 +load()
方法進行調用,是直接使用函數內存地址的方式 (load_method)(cls, SEL_load);
而不是使用發送消息 objc_msgSend
的方式,父類 TestClass
的 +load()
方法最早被調用,然後是子類和分類,對於多個分類的 +load()
的調用順序的前後,取決於編譯順序,測試一下,咱們在 Bulid Phases->Compile Sources
調整分類的編譯順序 bash
TestClass+Z
的
+load()
方法先於
TestClass+Y
被調用
+load()
方法的調用是在 main()
函數以前,而且不須要主動調用,程序啓動會把全部的文件加載,文件若是重寫了 +load()
方法,主類、子類、分類都會加載調用 +load()
方法;+load()
是在 main()
函數以前調用,因此在這個方法裏面不要做耗時操做或者阻塞的操做,會影響啓動速度;main()
函數以前自動調用,+load()
方法調用的時候使用者根本就不能肯定本身要使用的對象是否已經加載進來了,因此千萬不能在這裏初始化對象;+load()
方法中進行 Method Swizzle
操做,交換方法。+initialize()
方法是在類或它的子類收到第一條消息以前被調用的,這裏所指的消息包括實例方法和類方法的調用,也就是說 +initialize()
方法是以懶加載的方式被調用的,若是程序一直沒有給某個類或它的子類發送消息,那麼這個類的 +initialize()
方法是永遠不會被調用的,關於調用,咱們一樣用代碼進行測試函數
TestClass
實現 + initialize()
方法,子類和分類中不實現,分別以下調用TestClass *class1 = [[TestClass alloc] init];
TestClass *class2 = [[TestClass alloc] init];
// TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
// TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
// TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
// TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
// TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
複製代碼
TestClass *class1 = [[TestClass alloc] init];
TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
複製代碼
// TestClass *class1 = [[TestClass alloc] init];
// TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
複製代碼
會發現,無論咱們建立 TestClass
幾個對象,[TestClass initialize]
只被調用一次,而若是建立了 TestClassSubClass
對象,不管是否建立 TestClass
對象,[TestClass initialize]
都會調用兩次,可見當子類未實現 +initialize()
方法,會調用父類 +initialize()
方法。測試
TestClass
和子類中分別實現 + initialize
方法TestClass *class1 = [[TestClass alloc] init];
TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
複製代碼
// TestClass *class1 = [[TestClass alloc] init];
// TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
複製代碼
+ initialize()
方法,初始化都會至少去調用一次父類的
+ initialize()
方法,而若是自身實現了
+ initialize()
方法,那麼繼續調用本身的
+ initialize()
方法,若是未實現,則去調用父類的
+ initialize()
方法
TestClass
和子類、分類中分別實現 + initialize()
方法TestClass *class1 = [[TestClass alloc] init];
TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
複製代碼
// TestClass *class1 = [[TestClass alloc] init];
// TestClass *class2 = [[TestClass alloc] init];
TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
複製代碼
+ initialize()
方法,變成了調用
TestClass+Y
的
+ initialize()
方法,這是由於最後被編譯的
TestClass+Y
中的
+ initialize()
方法覆蓋了主類的
+ initialize()
方法
+ initialize()
方法會比子類先執行;+ initialize()
方法時,會調用父類 + initialize()
方法,子類實現 + initialize()
方法時,會覆蓋父類 + initialize()
方法;Category
都實現了 + initialize()
方法,會覆蓋類中的方法,只執行一個(會執行Compile Sources
列表中最後一個 Category
的 + initialize()
方法)。TestClass
和子類分別實現 -init()
方法TestClassSubClass *subClass1 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass2 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass3 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass4 = [[TestClassSubClass alloc] init];
TestClassSubClass *subClass5 = [[TestClassSubClass alloc] init];
複製代碼
-init()
方法,而後調用自身的
-init()
方法,而且每次初始化時都會調用
只在 TestClass
實現 -init()
方法ui
調用結果以下 spa
-init()
方法時,每初始化一個對象,只會調用一次父類的 -init()
方法 +load()
和 +initialize()
都會在實例化對象以前調用,前者是在 main()
函數以前,後者是在 main()
函數以後;+load()
和 +initialize()
方法都不會顯式的調用父類的方法而是自動調用,即便子類沒有 +initialize()
方法也會調用父類的方法,+load()
方法不會調用父類;+load()
和 +initialize()
方法內部使用了鎖,所以他們是線程安全的,實現時要儘量簡單,避免線程阻塞,不要再次使用鎖;+load()
方法經常使用來 method swizzle
,+initialize()
經常用於初始化全局變量和靜態變量。