+ (void) load;
如果一個類實(shí)現(xiàn)了load方法遏乔,在調(diào)用這個方法前會首先調(diào)用父類的load方法义矛。而且這個過程是自動完成的,并不需要我們手動實(shí)現(xiàn).
1盟萨、load方法在類或分類加載到runtime的時候調(diào)用凉翻;
2、load方法只調(diào)用一次捻激;
3噪矛、load方法調(diào)用順序:父類----子類----分類
// Parent.m
+ (void)load {
NSLog(@"Load Class Parent");
}
// Child.m,繼承自Parent
+ (void)load {
NSLog(@"Load Class Child");
}
// Child+load.m铺罢,Child類的分類
+ (void)load {
NSLog(@"Load Class Child+load");
}
// 運(yùn)行結(jié)果:
/*
load[11789:1435378] Load Class Parent
load[11789:1435378] Load Class Child
load[11789:1435378] Load Class Child+load
*/
如果一個類沒有實(shí)現(xiàn)load方法,那么就不會調(diào)用它父類的load方法.
在Compile Sources中残炮,文件的排放順序就是其裝載順序韭赘,自然也就是load方法調(diào)用的順序。這一點(diǎn)也證明了load方法中會自動調(diào)用父類的方法势就。簡單情況下我們可以辨別出各個類的load方法調(diào)用的順序泉瞻,但永遠(yuǎn)不要依賴這個順序完成你的代碼邏輯。一方面苞冯,這在后期的開發(fā)中極容易導(dǎo)致錯誤袖牙,另一方面,你實(shí)際上并不需要這么做舅锄。
用法
由于調(diào)用load方法時的環(huán)境很不安全鞭达,我們應(yīng)該盡量減少load方法的邏輯。另一個原因是load方法是線程安全的,它內(nèi)部使用了鎖畴蹭,所以我們應(yīng)該避免線程阻塞在load方法中坦仍。
一個常用場的地方是在load方法中實(shí)現(xiàn)Method Swizzle
+ (void)load {
Method originalFunc = class_getInstanceMethod([self class],
@selector(originalFunc));
Method swizzledFunc = class_getInstanceMethod([self class],
@selector(swizzledFunc));
method_exchangeImplementations(originalFunc, swizzledFunc);
}
除了Method Swizzle,別的邏輯都不應(yīng)該放在load方法中實(shí)現(xiàn)叨襟。
+ (void)initialize
這個方法在第一次給某個類發(fā)送消息時調(diào)用(比如實(shí)例化一個對象)繁扎,并且只會調(diào)用一次。initialize方法實(shí)際上是一種惰性調(diào)用糊闽,也就是說如果一個類一直沒被用到梳玫,那它的initialize方法也不會被調(diào)用,這一點(diǎn)有利于節(jié)約資源右犹。
1提澎、initialize在類第一次收到消息的時候調(diào)用;
2傀履、initialize有可能調(diào)用多次虱朵;(如果子類沒有實(shí)現(xiàn)initialize方法,則子類第一次收到消息的時候會先調(diào)用父類的initialize方法)
3钓账、initialize嗲用順序:父類----子類(如果有分類碴犬,分類中的initialize會覆蓋子類,子類中的方法不會調(diào)用)
+ (void)initialize {
NSLog(@"InitializeParent, caller Class %@", [self class]);
}
// Child.m
// 注釋掉initialize方法
//main.m
Child *child = [Child new];
運(yùn)行結(jié)果如下:
load[12772:1509345] Initialize Parent, caller Class Parent
load[12772:1509345] Initialize Parent, caller Class Child
這是因?yàn)樵趧?chuàng)建子類對象時梆暮,首先要創(chuàng)建父類對象服协,所以會調(diào)用一次父類的initialize方法,然后創(chuàng)建子類時啦粹,盡管自己沒有實(shí)現(xiàn)initialize方法偿荷,但還是會調(diào)用到父類的方法。
雖然initialize方法對一個類而言只會調(diào)用一次唠椭,但這里由于出現(xiàn)了兩個類跳纳,所以調(diào)用兩次符合規(guī)則,但不符合我們的需求贪嫂。正確使用initialize方法的姿勢是這樣的:
//Parent.m
+ (void)initialize {
if (self == [Parent class]) {
NSLog(@"Initialize Parent, caller Class %@", [self class]);
}
}
加上判斷后寺庄,就不會因?yàn)樽宇惗{(diào)用到自己的initialize方法了。
用法
initialize方法主要用來對一些不方便在編譯期初始化的對象進(jìn)行賦值力崇。比如NSMutableArray這種類型的實(shí)例化依賴于runtime的消息發(fā)送斗塘,所以顯然無法在編譯器初始化:
//Parent.m
static int someNumber = 0; // int類型可以在編譯期賦值
static NSMutableArray *someObjects;
+ (void)initialize {
if (self == [Parent class]) {
// 不方便編譯期復(fù)制的對象在這里賦值
someObjects = [[NSMutableArray alloc] init];
}
}
總結(jié)
1、load和initialize方法都會在實(shí)例化對象之前調(diào)用亮靴,以main函數(shù)為分水嶺馍盟,前者在main函數(shù)之前調(diào)用,后者在之后調(diào)用茧吊。這兩個方法會被自動調(diào)用贞岭,不能手動調(diào)用它們八毯。
2、load和initialize方法都不用顯示的調(diào)用父類的方法而是自動調(diào)用曹步,即使子類沒有initialize方法也會調(diào)用父類的方法宪彩,而load方法則不會調(diào)用父類。
3讲婚、load方法通常用來進(jìn)行Method Swizzle尿孔,initialize方法一般用于初始化全局變量或靜態(tài)變量。
4筹麸、load和initialize方法內(nèi)部使用了鎖活合,因此它們是線程安全的。實(shí)現(xiàn)時要盡可能保持簡單物赶,避免阻塞線程白指,不要再使用鎖