個人學知識還是想盡量學的明白些,否則覺著不順暢,雖然很早就看蘋果官方文檔,https://developer.apple.com/library/ios/documentation/General/Conceptual/DevPedia-CocoaCore/Initialization.html,人家就是建議這樣寫
if (self = [super init]) { // equivalent to "self does not equal nil"
date = [[NSDate date] retain];
}
return self;
}
但是自己還是有疑惑,疑惑在于兩點:
1.這樣寫不是把[super init]出來的父類指針賦值給了子類self了么.這樣一來,我需要的子類self不就變成了父類的self了么?可是實際使用時我們為啥沒出現任何問題呢?
2.為什么要這樣寫?或者說這樣寫的意義在于哪里?
首先闡述我理解的第一個問題,Google了,也百度了,有人對此提出疑問,卻沒人針對性的給與解答,可能只有問題來自自己的思考才會做出十分針對性的回答.(請允許我說的盡量直白些,這樣更有利于表達清楚).查看了說的比較好的文字有以下兩個,一個是國內的,一個是國外的
1.http://forums.macrumors.com/threads/super-init-vs-if-self-super-init.532527/
2.http://www.cnblogs.com/tangbinblog/p/4034890.html
當然還有簽名蘋果關于初始化以及alloc的描述
各有各的理解,不過我還是覺得綜合說一下,加上自己的理解有助于大家的互相學習:
要解答第一個問題先說說這個self究竟是什么,其實剛開始接觸面向對象語言的時候就見過,記得大學的時候老師反復強調的就是"指向對象自己的指針",那么粗略的說這句話沒錯,在學習oc后咱們幾乎都看到過這樣的描述"self代表著當前方法的調用者",
這里有必要說的更直白些,我們可以想想,什么時候我們會寫出這個self,只有在方法里,才會寫出來,所以這么說是沒有問題的,我們可以簡單的結合代碼來看,比如對象方法里你打印self是一個內存地址,或者說是指針,類方法里呢,打印出來的是對應的類名,也就是class類型,
"self代表著當前方法的調用者"這句話說的對,但是似乎還有疑問,當前方法的調用者究竟該如何描述它,在層層繼承關系中,這個self既然是個地址也就是指針,那么它代表的是誰的指針,runtime在消息機制里又是如何和self交互的,
那么先看看init方法的配對使用,也就是oc的慣用方法,[UIView alloc]init,其實,在任意一個對象方法里打印self,我們都會得到一個相同的地址,也就是說alloc在分配給一個子類內存的時候,self已經出現,runtime在發送消息的時候,self是隱含參數之一,self是子類接收消息的入口,咱們在寫下面這樣的init方法時看似調用了[super init],也就是父類的方法,
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
但是我們還是在子類里調用的,目前alloc在內存里也完全是按照子類需要的內存大小分配的內存空間,既然在消息機制里,需要消息的接收主體,或者說入口,同時內存里又是為子類分配的內存,所以說在子類里調用任何方法,包括用super調用父類的方法,消息的接收實體都是當前子類,super只是告訴編譯器查找方法的時候再父類方法列表里 去查找.根本不可能越過這個子類把消息直接發送到父類里去.趁熱打鐵看下面的代碼
#import "WYControl.h"
@implementation WYControl
//這是父類
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
#import "WYSubControl.h"
@implementation WYSubControl
//這是繼承上一個類的子類
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
當你把斷點打在 父類方法第一句時,你會發現此時父類的打印出來的self也是子類,也就是說明了,
父類此時的方法調用者依然是子類self,父類儼然成為了子類的一部分,在實例化子類時父類事例self是不存在的.所以回到第一個問題,子類alloc后分配出現了self,這個self ,在[super init]鏈中只有一個唯一的self,就是事例子類自己的self,不存在其他self,所以self = [super init]沒有出現把父類self賦值給子類self的事情.所以不會有任何問題.
闡述第二個問題:
這樣做的意義在于,我們想要用到子類的實例,比如我們想實例一個button,那么我們必將用到button繼承于uiview的某些屬性,如果由于某些原因[super init]在初始化他的屬性時沒有成功,在父類的init方法里返回了一個nil,那么我們得到的button實例的self 也就是這個實例將會同樣是nil,不會傻傻的用一個殘疾的self去做事情.當然還有其他情況,比如類簇等等,蘋果前面的鏈接里說的很清楚.當然有時候我們寫成了self == [super init]也是ok的,這樣寫的風險就是排除不了父類返回nil的情況,因為self 與[super init]的結果本來正常情況下就應該是相等的!所以大多數情況下,這個等式都成立,所以寫成
- (instancetype)init
{
if (self ==[super init]) {
}
return self;
}
也一樣可以,但是這樣寫是不對的.靜態分析時就會出現警告.
如果那里說的不對請給與指出,謝謝!如果大神們有更深入底層的理解,希望也寫出來.如果誰有相應的博客地址請留個言!萬分感謝!!!