2014-01-18 208 views
5

任何人都可以解釋爲什麼我們需要在+initialize方法中包含if (self == SomeClass class)執行-init vs. +初始化

我發現類似的問題(見下表),但沒有發現任何具體的澄清:

  1. Objective-C: init vs initialize
  2. Should +initialize/+load always start with an: if (self == [MyClass class]) guard?

大家說,如果你不執行/在子類中覆蓋+initialize,那麼它將調用父類兩次。

任何人都可以特別解釋那部分,特別是爲什麼它會調用父類兩次?

最後,爲什麼沒有當我們從NSObject的,在這裏我們創建一個自定義-init方法,並調用self = [super init];繼承的類實現+initialize發生。

+0

初始化和初始化沒有任何關係。 – rmaddy

+0

@rmaddy在'-init'裏面你有'self = [super init];'調用父母的'+ initialize',還是我不正確? – makaed

+1

你是不正確的。在調用任何其他類或實例方法之前,每個類都調用一次initialize。 – rmaddy

回答

4

-init+initialize是完全不同的東西。第一個用於初始化實例;第二個用於初始化類別

第一次給任何給定的類發送消息時,運行時確保在其上調用+initialize及其超類。超類首先被初始化,因爲它們需要在任何子類自身初始化之前做好準備。

所以,第一個是時間YourSubclass被傳遞消息,運行時會做這樣的事情:

[NSObject initialize]; 
[YourClass initialize]; 
[YourSubclass initialize]; 

(雖然這是不太可能,這將是第一次NSObject被傳遞消息,所以可能它不」噸需要在這一點上被初始化。這只是一個例子。)

如果YourSubclass沒有實現+initialize,然後上面顯示的[YourSubclass initialize]調用將實際調用+[YourClass initialize]。這只是工作中的正常繼承機制。這將會第二次調用+[YourClass initialize]

由於在+initialize方法中完成的工作通常是應該只做一次的事情,所以警衛if (self == [TheClassWhoseImplementationThisMethodIsPartOf class])是必要的。此外,這項工作通常假設self是指當前正在編寫的課程,所以這也是警衛的原因。

您引用的第二個答案指出了一個例外,即使用+setKeys:triggerChangeNotificationsForDependentKey:方法註冊KVO相關鍵的舊式機制。該方法特定於它所調用的實際類,而不是任何子類。你應該避免它,並使用更現代的+keyPathsForValuesAffectingValueForKey:+keyPathsForValuesAffecting<Key>方法。如果你必須用舊的方式,把那部分放在警衛之外。此外,這種類的子類必須調用super,這通常不會完成。

更新:

一個+initialize方法通常不應通過,因爲運行時已經初始化超打電話super。當且僅當已知超類使用舊機制來註冊依賴鍵時,則任何子類都必須通過super來調用。

-init的情況下不存在同樣的擔心,因爲運行時在調用您的函數之前不會自動調用超類的init方法。事實上,如果你的init方法沒有調用super,那麼沒有任何東西會初始化超類的實例的「部分」。

+0

你的例子中的'TheClassWhoseImplementationThisMethodIsPartOf'是'YourClass'嗎? – makaed

+1

在'+ [YourClass initialize]'的實現裏面,是的。我試圖使它一般。 –

0

你引用的問題有很好的接受答案。總之,+initialize由運行時在每個類中調用,因此對於具有N個子類的超類,它將在超類上被調用N + 1次(對於繼承它的每個子類,它會直接調用一次)。同樣的事情,如果一個子類覆蓋它並調用超級。

你可以通過在超類級別詢問來防範這種情況,「這是我的系統直接初始化,而不是由我的子類繼承或調用'super'嗎?」

if (self == [ThisSuperclass self]) {} 

-init用於初始化類的實例和由運行時等+initialize不調用默認情況下。實例繼承它們的-init實現,可以覆蓋繼承的實現,並且還可以通過調用[super init];來享受繼承實現的好處。

+0

因此''initialize'在任何情況下都由運行時調用,而不需要用戶編寫代碼?如果是的話,我想知道在什麼情況下,會在子類中調用super上的「+ initialize」? – makaed

+1

@danh,不僅當子類調用'super'時,該方法將被調用兩次。當子類不執行'+ initialize'時,這是目前最常見的情況。 –

+0

我明白了。謝謝,我編輯了。 – danh

5

想象一下,你有一個超類,它實現了+initialize和一個不支持的子類。

@interface SuperClass : NSObject @end 
@implementation SuperClass 
+(void)initialize { 
    NSLog(@"This is class %@ running SuperClass +initialize", self); 
} 
@end 

@interface SubClass : SuperClass @end 
@implementation SubClass 
// no +initialize implementation 
@end 

使用超類。這引起了對+[SuperClass initialize]的呼叫。

[SuperClass class]; 
=> This is class SuperClass running SuperClass +initialize 

現在使用子類。運行時查找​​中的+initialize的實現,但未找到任何內容。然後它在SuperClass中查找繼承的實現並找到它。繼承的實現被調用,即使它已經代表SuperClass本身調用一次:

[SubClass class]; 
=> This is class SubClass running SuperClass +initialize 

警衛允許您執行必須在最多一次運行工作。之後任何對+initialize的呼叫與self都有不同的等級,所以守衛可以忽略它們。