寫高質量OC程式碼52建議總結:51.load和initialize
阿新 • • 發佈:2019-02-18
有時候,類必須先執行某些初始化操作才能正常執行,先說下load方法:
+(void)load
加入執行期系統中的每個類及分類必定會呼叫此方法,只調用一次(在程式啟動的時候)。如果類和所屬的分類都定義了load方法,先呼叫類中的,再呼叫分類中的。
load不遵循繼承規則,如果類本身沒實現load方法,不管父類是否實現都不會被呼叫。如果都實現了,類比分類先呼叫load。
load中的程式碼必須精簡。甚至能不寫東西就別寫東西。。。如果load中包含繁瑣的程式碼,程式在執行期間就會變得無響應。load主要用於除錯程式,正常編碼一般不需要。
EOCBaseClass initialize,EOCSubClass initialize
所以,通常這樣實現:
+(void)initialize{
if(self == [EOCBaseClass class]) {
NSLog(@"%@ initialize", self);
}
}
控制檯只會輸出一條資訊了,EOCBaseClass initialize。
load和initialize,在裡面設定一些狀態使本類可以正常運作就可以了,不要加入太複雜的程式碼。我們無法控制類初始化的時間,不可控。假如一個類的初始化方法很複雜,其中可能直接或間接用到其他的類,本類的初始化方法此時還沒實行,如果其他類初始化的時候需要本類的一些資料,就會產生錯誤。
如果某個全域性狀態無法在編譯器初始化可以放到initialize中。
總結:
1.load方法不參與覆寫機制。
2.initialize參與覆寫機制,通常在其中判斷當前要初始化哪個類。
3.load和initialize中的程式碼都應該精簡,保證程式的響應能力。
4.無法在編譯器初始化的全域性常量,可以在initialize中初始化。
+(void)load
加入執行期系統中的每個類及分類必定會呼叫此方法,只調用一次(在程式啟動的時候)。如果類和所屬的分類都定義了load方法,先呼叫類中的,再呼叫分類中的。
load方法的問題在於,執行的時候系統處在“脆弱時期”,執行子類load之前必定會執行超類load,程式碼如果依賴了其他類,相關類中的load方法也會先執行,但是無法判斷各個類的載入順序。所以在load中使用其他類的方法是不安全的。例如:
+(void)load{
NSLog(@"Loading EOCClassB");
EOCClassA *object = [EOCClassA new];
}
nslog沒問題,Foundation框架一定在執行load前就載入系統了。但是在EOCClassB中執行EOCClassA中的方法就不安全了,因為此時不確定EOCClassA已經載入好了。load不遵循繼承規則,如果類本身沒實現load方法,不管父類是否實現都不會被呼叫。如果都實現了,類比分類先呼叫load。
load中的程式碼必須精簡。甚至能不寫東西就別寫東西。。。如果load中包含繁瑣的程式碼,程式在執行期間就會變得無響應。load主要用於除錯程式,正常編碼一般不需要。
要執行與類相關的初始化操作還可以覆寫下面的方法:
+(void)initialize;
程式會在首次使用該類的時候呼叫,只調用一次,由系統呼叫不能手動呼叫。它是惰性呼叫的,如果用到了該類才會呼叫該方法,沒用到就不呼叫。這點和load不同(load必須把所有類都執行完程式才能繼續)。系統在呼叫該方法時是安全的,可以安全的呼叫並使用任意類中的任意方法。系統也會保證initialize的執行緒安全,只有執行initialize的執行緒可以操作類。其他執行緒先阻塞等待initialize執行完。還有一點,initialize遵循繼承協議,父類實現了該方法子類沒有實現。執行時,系統都會呼叫該方法。
@interface EOCBaseClass : NSObject
@end
@implementation EOCBaseClass
+(void)initialize{
NSLog(@"%@ initialize", self);
}
@end
@interface EOCSubClass : EOCBaseClass
@end
@implementation EOCSubClass
@end
即使EOCSubClass沒有實現initialize,他也會受到訊息。EOCBaseClass initialize,EOCSubClass initialize
所以,通常這樣實現:
+(void)initialize{
if(self == [EOCBaseClass class]) {
NSLog(@"%@ initialize", self);
}
}
控制檯只會輸出一條資訊了,EOCBaseClass initialize。
load和initialize,在裡面設定一些狀態使本類可以正常運作就可以了,不要加入太複雜的程式碼。我們無法控制類初始化的時間,不可控。假如一個類的初始化方法很複雜,其中可能直接或間接用到其他的類,本類的初始化方法此時還沒實行,如果其他類初始化的時候需要本類的一些資料,就會產生錯誤。
如果A先初始化,隨後B初始化,會在自己的初始化方法中呼叫A的doSomething方法,此時A的內部資料還沒準備好。static id EOCClassAInternalData; @interface EOCClassA : NSObject @end static id EOCClassBInternalData; @interface EOCClassB : NSObject @end @implementation EOCClassA +(void)initialize{ if (self == [EOCClassA class]) { //[EOCClassB doSomething]; EOCClassAInternalData = [self setupInternalData]; } } @end @implementation EOCClassB +(void)initialize{ if (self == [EOCClassB class]) { //[EOCClassA doSomething]; EOCClassBInternalData = [self setupInternalData]; } } @end
如果某個全域性狀態無法在編譯器初始化可以放到initialize中。
整數可以在編譯器編譯,可變陣列不行,它是個OC物件,建立例項的時候必須先啟用系統。@interface EOCClass : NSObject @end static const int kInterval = 10; static NSMutableArray *kSomeObjects; @implementation EOCClass +(void)initialize{ if (self == [EOCClass class]) { kSomeObjects = [NSMutableArray new]; } } @end
總結:
1.load方法不參與覆寫機制。
2.initialize參與覆寫機制,通常在其中判斷當前要初始化哪個類。
3.load和initialize中的程式碼都應該精簡,保證程式的響應能力。
4.無法在編譯器初始化的全域性常量,可以在initialize中初始化。