self = [super init] 這個問題一直不太明白,今天研究了一下,在stackoverflow找到了下面的答案:
http://stackoverflow.com/questions/2956943/why-should-i-call-self-super-init
我對這些答案簡單翻譯總結下:
要明白這個問題,首先要知道self 是什么東西,我們什么時候會用到self。
self指針,不是在實例中的保存的真實指針,而是一個隱藏的函數參數。比如我們調用 [person getName]; 時,系統會翻譯為
id objc_msgSend(id theReceiver, SEL theSelector, ...)
這種調用,其中的 theReceiver,就是我們在實例對象的方法里可以用到的self,其實它僅僅是一個隱藏的函數參數。
看完了self是什么,在看看super是什么,這里,可以參見這篇博文,寫得非常出色:
http://chun.tips/blog/2014/11/05/bao-gen-wen-di-objective[nil]c-runtime(1)[nil]-self-and-super/
我把重點說一下:
調用如下代碼:
NSLog(@"%@", NSStringFromClass([self class])); NSLog(@"%@", NSStringFromClass([super class]));
使用 clang -rewrite-objc 這個命令后,得到的中間代碼有如下關鍵部分:
(void *)objc_msgSend)((id)self, sel_registerName("class")
(void *)objc_msgSendSuper)((__rw_objc_super){ (id)self, (id)class_getSuperclass(objc_getClass("Son")) }, sel_registerName("class")
注意,用了super去調用,其實還是把self的值傳遞進去了,但是,多傳遞了一個類名,這里就是“Son”,並且使用了objc_msgSendSuper進行消息傳遞。
簡單地說,super和self 都是在函數調用時,隱藏傳遞進去的一個參數,但是,super會從父類方法列表中先進行索引,如果找到了函數實現,就不再調用子類的函數實現了。
看過上面的解釋,其實,super和self真正指向的都是已經被分配內存的對象,在 init方法中,就是alloc后,沒有初始化的一段內存空間。[super init] 就是把這塊內存空間先傳遞給父類,去父類調用父類的init方法,返回一段部分初始化好內存空間。為了方便理解,我畫了一個大概的圖:

在[super init] 之后,父類的變量應該被初始化完畢,而子類的變量還沒有初始化。
在一般情況下,寫不寫 self = [super init] 都無關緊要,因為 [super init] 在一般情況下的返回值,都是一段已經初始化好一部分的內存。我們自己繼承NSObject的類,如果沒用什么特殊方法(什么叫特殊?見下面的class cluster),就不需要寫這個 self =。
但是在特殊情況下,比如分配出錯,那么 [super init] 會返回空,表明錯誤,這時,如果不把 self 設置為nil,而是繼續指向alloc后的那塊內存,之后的操作就會產生問題。
還有一種特殊情況,叫做Class Cluster,翻譯中文的話,類族,官方文檔 https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/ClassClusters/ClassClusters.html
再看一篇好的博文:
http://blog.sunnyxx.com/2014/12/18/class-cluster/
按照博客里的方法,我也實驗了一下,截圖如下:

obj1 , obj3 不但類型不同,而且地址也不同!我如果繼承了NSArray(會這樣操作嗎?沒有實驗),並且重寫了init方法,那么必須在init中,明確寫出 self =,不然,就根本得不到正確的對象!所以說,在你不知道你的父類是否進行了這種操作時,最好使用在子類初始化時使用 self = [super init],來確保你寫的子類是正確的。
這個問題的本質,就是 init方法,不一定會使用alloc所產生的內存去初始化,它可以重新分配一塊內存,初始化后返回!
