load和initialize的區別

演示代碼1下載地址
演示代碼2下載地址

它們的相同點在于:

方法只會被調用一次(其實這是相對runtime來說的,后邊會做進一步解釋)。

Apple的文檔很清楚地說明了initialize和load的區別在于:

load是只要類所在文件被引用就會被調用,而initialize是在類或者其子類的第一個方法被調用前調用。所以如果類沒有被引用進項目,就不會有load調用;但即使類文件被引用進來,但是沒有使用,那么initialize也不會被調用。

總結:

+(void)load +(void)initialize
執行時機 在程序運行后立即執行 在類的方法第一次被調時執行
若自身未定義,是否沿用父類的方法?
類別中的定義 全都執行,但后于類中的方法 覆蓋類中的方法,只執行一個

文檔也明確闡述了方法調用的順序:

父類(Superclass)的方法優先于子類(Subclass)的方法,類中的方法優先于類別(Category)中的方法。
不過還有很多地方是文章中沒有解釋詳細的。所以再來看一些示例代碼來明確其中應該注意的細節,如下所示,創建三個類。

示例代碼1

@interface SuperClass : NSObject

@end

@implementation SuperClass

+ (void) initialize {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

+ (void) load {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
    
}

@end
@interface ChildClass : SuperClass

@end

@implementation ChildClass

+ (void) initialize {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
    Insideinitialize * obj = [[Insideinitialize alloc] init];
    [obj objectMethod];
//    [obj release];
}
@end
@interface Insideinitialize : NSObject
- (void)objectMethod;
@end

@implementation Insideinitialize
- (void)objectMethod {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

+ (void) initialize {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

+ (void) load {
    NSLog(@"%s", __FUNCTION__);
}
@end

這個示例代碼中,一個SuperClass實現了+(void)load和+(void)initialize方法(實際上應該算是重寫覆蓋了NSObject的這兩個方法);ChildClass繼承于SuperClass,但是只重寫+(void)initialize沒有+(void)load;Insideinitialize類也有+(void)load和+(void)initialize方法,它在ChildClass的i+(void)initialize方法中被構建出一個對象。類中的每個函數的實現都非常簡單,只是輸出類名和方法名。除了Insideinitialize的+(void)load方法只輸出了類名,沒有使用[self class]。

首先我們在Xcode的項目中只簡單import這些類,而不去使用他們的,然后運行項目就會得到下邊的結果

SuperClass +[SuperClass initialize]
SuperClass +[SuperClass load]
Insideinitialize +[Insideinitialize load]

就像Apple的文檔中說的一下,只要有引用runtime就會自動去調用類的+(void)load方法。不過從輸出中,我們還發現SuperClass的+(void)initialize也被調用了,而且是在+(void)load之前被執行;而Insideinitialize的+(void)initialize并沒有執行。這是因為在SuperClass的+(void)load方法中,我們調用了類的class方法([self class]),這就符合文檔中對+(void)initialize的說明:在類的第一個方法被調用前調用。同時也說明runtime對+(void)load的調用并不視為類的第一個方法。而ChildClass因為沒有用到,所以+(void)initialize的方法被沒有被執行,而且它也沒有去執行父類的+(void)load方法(雖然它有繼承下該方法)

+(void)load和+(void)initialize可當做普通類方法(Class Method)被調用

接著, 在程序中讓ChildClass直接調用load:

@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    [ChildClass load];
}

@end

[ChildClass load];
程序正常運行,并輸出了結果:

 SuperClass +[SuperClass initialize]
SuperClass +[SuperClass load]
 +[Insideinitialize load]
 ChildClass +[ChildClass initialize]
 Insideinitialize +[Insideinitialize initialize]
Insideinitialize -[Insideinitialize objectMethod]
 ChildClass +[SuperClass load]

前面三個結果跟之前一樣,不過之后ChildClass的+(void)initialize也被自動執行調用,并且我們可以在其中安全創建出Insideinitialize類并使用它,而Insideinitialize因為調用alloc方法是第一次使用類方法, 所以激發了Insideinitialize的+(void)initialize。

另一個方面,ChildClass繼承下了+(void)load而且可以被安全地當做普通類方法(Class Method)被使用。這也就是我之前所說的load和initialize被調用一次是相對runtime而言(比如SuperClass的initialize不會因為自身load方法調用一次,又因為子類調用了load又執行一次),我們依然可以直接去反復調用這些方法。
子類會調用父類的+(void)initialize

接下來,我們再修改一下SuperClass和ChildClass:去掉SuperClass中的+(void)load方法;讓ChildClass來重寫+(void)load,但是去掉+(void)initialize。

SuperClass +[SuperClass initialize]
ChildClass +[SuperClass initialize]
ChildClass +[ChildClass load]

和之前一樣,+(void)load會引起+(void)initialize。也很Apple文檔中講得那樣,子類方法的調用會激起父類的+(void)initialize被執行。不過我們也看到雖然ChildClass沒有定義+(void)initialize,但是它會使用父類的+(void)initialize。而之前的示例,我們看到子類并不會在runtime時去使用父類的+(void)load,也就是說只有新定義的+(void)load才會被runtime去調用執行。

類別(Category)中的+(void)load的+(void)initialize

我們再來看看類實現(@implementation)和類的類別(Category)中+(void)load和+(void)initialize的區別。

示例代碼2

/******* Interface *******/
@interface MainClass : NSObject
@end

/******* Category Implementation *******/
@implementation MainClass(Category)

+ (void) load {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

+ (void) initialize {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

@end

@implementation MainClass(OtherCategory)

+ (void) load {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

+ (void) initialize {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

@end

/******* Implementation *******/
@implementation MainClass

+ (void) load {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

+ (void) initialize {
    NSLog(@"%@ %s", [self class], __FUNCTION__);
}

@end

簡單運行后的打印結果如下:

MainClass +[MainClass(OtherCategory) initialize]
MainClass +[MainClass load]
MainClass +[MainClass(Category) load]
MainClass +[MainClass(OtherCategory) load]

同樣的+(void)initialize優先于+(void)load先執行。但是很明顯的不同在于,只有最后一個類別(Category)的+(void)initialize執行,其他兩個都被隱藏。而對于+(void)load,三個都執行,并且如果Apple的文檔中介紹順序一樣:
先執行類自身的實現,再執行類別(Category)中的實現。

Runtime調用+(void)load時沒有autorelease pool

最后再來看一個示例

@interface MainClass : NSObject
@end

@implementation MainClass

+ (void) load {
    NSArray *array = [NSArray array];
    NSLog(@"%@ %s", array, __FUNCTION__);
}

@end

運行這段代碼,Xcode給出如下的信息:

objc[84934]: Object 0x10a512930 of class __NSArrayI autoreleased with no pool in place - just leaking - break on objc_autoreleaseNoPool() to debug
2012-09-28 18:07:39.042 ClassMethod[84934:403] (
) +[MainClass load]

其原因是runtime調用+(void)load的時候,程序還沒有建立其autorelease pool,所以那些會需要使用到autorelease pool的代碼,都會出現異常。這一點是非常需要注意的,也就是說放在+(void)load中的對象都應該是alloc出來并且不能使用autorelease來釋放。

不需要顯示使用super調用父類中的方法

當我們定義-(id)init和-(void)dealloc方法時,我們總是需要使用super關鍵字來調用父類的方法,讓父類也完成相同的操作。這是因為對對象的初始化和銷毀過程,Objective-C不像C++,C#那樣會自動調用父類默認構造函數。因此我們總是需要將這兩個函數寫成這樣:

- (id)init {
    if ((self = [super init])) {
        //do initialization
    }
    
    return self;
}

- (void)dealloc {
    //do release
    
    [super dealloc];
}

但是+(void)initialize和+(void)load不同,我們并不需要在這兩個方法的實現中使用super調用父類的方法:

+ (void)initialize {
    //do initialization thing
    [super initialize];
}

+ (void) load {
    //do some loading things
    [super load];
}

super的方法會成功調用,但是這是多余的,因為runtime對自動對父類的+(void)load方法進行調用,而+(void)initialize則會隨子類自動激發父類的方法(如Apple文檔中所言)不需要顯示調用。另一方面,如果父類中的方法用到的self(像示例中的方法),其指代的依然是類自身,而不是父類。

markdown表格制作方法:


|       Tables        |             +(void)load           |       +(void)initialize        |
| :-----------------: |:-----------------------:| :---------------------: |
|           執行時機         |  在程序運行后立即執行 | 在類的方法第一次被調時執行 |
| 若自身未定義,是否沿用父類的方法?|         否       |            是      |
|      類別中的定義        | 全都執行,但后于類中的方法  |  覆蓋類中的方法,只執行一個 |
Tables +(void)load +(void)initialize
執行時機 在程序運行后立即執行 在類的方法第一次被調時執行
若自身未定義,是否沿用父類的方法?
類別中的定義 全都執行,但后于類中的方法 覆蓋類中的方法,只執行一個
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,536評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內容