刨根問底:對於 self = [super init] 的思考

發表於2016-03-26

物件初始化有兩種方式:[class new][[class alloc] init]

對於後者,有分配和初始化的過程,alloc 從應用程式的虛擬地址空間上為該物件分配足夠的記憶體,並且將新物件的引用計數加1、將物件的成員變數初始為零,init 會做真正的初使化工作,為物件的例項變數賦予合理有用的值。

一般不推薦使用[class new],而推薦使用[[class alloc] new],檢視原始碼分析一下:

發現[class new]預設呼叫 [newObject init]方法,那麼我們無法使用自定義的初始化方法,多了更多的侷限性。那麼[class alloc] init] 會更方便, 當然[class alloc] init] 的設計也是由於歷史的原因。

為啥這麼寫?

我們知道alloc返回一個有效的未初始化的物件例項。對於selfalloc 返回的指標,同時可以在所有的方法作用域內訪問。

但是對於 super,它只是一個”編譯器指示符”,告訴編譯器在父類中搜尋方法的實現。

優先呼叫[super init] 是為了使超類完成它們自己的初始化工作。

那麼 if (self = [super init])又是做啥?

這裡是擔心父類初始化失敗,如果初始化一個物件失敗,就會返回nil,當返回nil的時候self = [super init]測試的主體就不會再繼續執行。如果不這樣做,你可能會操作一個不可用的物件,它的行為是不可預測的,最終可能會導致你的程式崩潰。

理解 Self & Super

看到網上一道經典的題目:

self表示當前這個類的物件,而super是一個編譯器標示符,和self指向同一個訊息接受者。在本例中,無論是[self class]還是[super class],接受訊息者都是Son物件,但superself不同的是,self呼叫class方法時,是在子類Son中查詢方法,而super呼叫class方法時,是在父類Father中查詢方法。

當呼叫[self class]方法時,會轉化為objc_msgSend函式,這個函式定義如下:

這時候就開始了訊息傳遞和轉發的過程,會先從Cache 中查詢方法,然後當前類,如果還是查詢不到會去父類,直至NSObject

對於NSObject類中,- (Class)class的實現如下:

所以列印結果為Son

當呼叫[super class]方法時,會轉化為objc_msgSendSuper,這個函式定義如下:

objc_msgSendSuper函式第一個引數super的資料型別是一個指向objc_super的結構體

結構體包含兩個成員,第一個是receiver,表示類的例項。第二個成員是記錄當前類的父類是什麼,會優先從Father這個類裡去找- (Class)class,然後進行訊息傳遞的過程。

會發現不管是self、還是super指向訊息接受者是一樣的,並且經過訊息傳遞,最終處理訊息的方法都是NSObject中的- (Class)class方法。

參考文章:

相關文章