NSObject類有兩種初始化方式
load
和initialize
+ (void)load;
對於加入運行期系統的類及分類,必定會調用此方法,且僅調用一次。
iOS會在應用程序啟動的時候調用load
方法,在main
函數之前調用
執行子類的load方法前,會先執行所有超類的load方法,順序為父類->子類->分類
在load方法中使用其他類是不安全的,因為會調用其他類的load方法,而如果關系復雜的話,就無法判斷出各個類的載入順序,類只有初始化完成後,類實例才能進行正常使用
load 方法不遵從繼承規則,如果類本身沒有實現load方法,那麼系統就不會調用,不管父類有沒有實現(跟下文的initialize有明顯區別)
盡可能的精簡load
方法,因為整個應用程序在執行load方法時會阻塞,即,程序會阻塞直到所有類的load方法執行完畢,才會繼續
load 方法中最常用的就是方法交換method swizzling
+ (void)initialize;
在首次使用該類之前由運行期系統(非人為)調用,且僅調用一次
惰性調用,只有當程序使用相關類時,才會調用
運行期系統會確保initialize
方法是在線程安全的環境中執行,即,只有執行initialize的那個線程可以操作類或類實例。其他線程都要先阻塞,等待initialize執行完
如果類未實現initialize
方法,而其超類實現了,那麼會運行超類的實現代碼,而且會運行兩次(load 第5點)
initialize 遵循繼承規則
初始化子類的的時候會先初始化父類,然後會調用父類的initialize
方法,而子類沒有覆寫initialize
方法,因此會再次調用父類的實現方法
鑒於此,initialize
方法實現如下:
+ (void)initialize { if (self == [People class]) { NSLog(@"%@ initialize", self); } }
initialize方法也需要盡量精簡,一般只應該用來設置內部數據,比如,某個全局狀態無法在編譯期初始化,可以放在initialize裡面。
static NSMutableArray *kSomeObjects; @implementation People + (void)initialize { if (self == [People class]) { kSomeObjects = [NSMutableArray new]; } }
1. 在加載階段,如果類實現了load方法,系統就會調用它,load方法不參與覆寫機制
2. 在首次使用某個類之前,系統會向其發送initialize消息,通常應該在裡面判斷當前要初始化的類,防止子類未覆寫initialize
的情況下調用兩次
3. load與initialize方法都應該實現得精簡一些,有助於保持應用程序的響應能力,也能減少引入“依賴環”(interdependency cycle)的幾率
4. 無法在編譯期設定的全局常量,可以放在initialize方法裡初始化