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


對象初始化有兩種方式:[class new][[class alloc] init]

對于后者,有分配和初始化的過程,alloc 從應(yīng)用程序的虛擬地址空間上為該對象分配足夠的內(nèi)存,并且將新對象的引用計(jì)數(shù)加1、將對象的成員變量初始為零,init 會做真正的初使化工作,為對象的實(shí)例變量賦予合理有用的值。

一般不推薦使用[class new],而推薦使用[[class alloc] init],查看源碼分析一下:

+ new 
{ 
    id newObject = (*_alloc)((Class)self, 0); 
    Class metaClass = self->isa; 
    if (class_getVersion(metaClass) > 1) 
    return [newObject init]; 
    else 
    return newObject; 
} 
 
//而 alloc/init 像這樣: 
+ alloc 
{ 
    return (*_zoneAlloc)((Class)self, 0, malloc_default_zone());  
} 
- init 
{ 
    return self; 
} 

發(fā)現(xiàn)[class new]默認(rèn)調(diào)用 allocinit方法,那么我們無法使用自定義的初始化方法,多了更多的局限性。那么[class alloc] init] 會更方便, 當(dāng)然[class alloc] init] 的設(shè)計(jì)也是由于歷史的原因。

為啥這么寫?

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

我們知道alloc返回一個(gè)有效的未初始化的對象實(shí)例。對于selfalloc 返回的指針,同時(shí)可以在所有的方法作用域內(nèi)訪問。

但是對于 super,它只是一個(gè)"編譯器指示符",告訴編譯器在父類中搜索方法的實(shí)現(xiàn)。

優(yōu)先調(diào)用[super init] 是為了使超類完成它們自己的初始化工作。

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

這里是擔(dān)心父類初始化失敗,如果初始化一個(gè)對象失敗,就會返回nil,當(dāng)返回nil的時(shí)候self = [super init]測試的主體就不會再繼續(xù)執(zhí)行。如果不這樣做,你可能會操作一個(gè)不可用的對象,它的行為是不可預(yù)測的,最終可能會導(dǎo)致你的程序崩潰。

理解 Self & Super

看到網(wǎng)上一道經(jīng)典的題目:

@implementation Son : Father
- (id)init
{
    self = [super init];
    if (self)
    {
        NSLog(@"%@", NSStringFromClass([self class]));
        NSLog(@"%@", NSStringFromClass([super class]));
    }
    return self;
}
@end

self表示當(dāng)前這個(gè)類的對象,而super是一個(gè)編譯器標(biāo)示符,和self指向同一個(gè)消息接受者。在本例中,無論是[self class]還是[super class],接受消息者都是Son對象,但superself不同的是,self調(diào)用class方法時(shí),是在子類Son中查找方法,而super調(diào)用class方法時(shí),是在父類Father中查找方法。

當(dāng)調(diào)用[self class]方法時(shí),會轉(zhuǎn)化為objc_msgSend函數(shù),這個(gè)函數(shù)定義如下:

id objc_msgSend(id self, SEL op, ...)  

這時(shí)候就開始了消息傳遞和轉(zhuǎn)發(fā)的過程,會先從Cache 中查找方法,然后當(dāng)前類,如果還是查找不到會去父類,直至NSObject

對于NSObject類中,- (Class)class的實(shí)現(xiàn)如下:

- (Class)class {  
    return object_getClass(self);  
}  

所以打印結(jié)果為Son

當(dāng)調(diào)用[super class]方法時(shí),會轉(zhuǎn)化為objc_msgSendSuper,這個(gè)函數(shù)定義如下:

id objc_msgSendSuper(struct objc_super *super, SEL op, ...)  

objc_msgSendSuper函數(shù)第一個(gè)參數(shù)super的數(shù)據(jù)類型是一個(gè)指向objc_super的結(jié)構(gòu)體

struct objc_super {
   __unsafe_unretained id receiver;
   __unsafe_unretained Class super_class;
};

結(jié)構(gòu)體包含兩個(gè)成員,第一個(gè)是receiver,表示類的實(shí)例。第二個(gè)成員是記錄當(dāng)前類的父類是什么,會優(yōu)先從Father這個(gè)類里去找- (Class)class,然后進(jìn)行消息傳遞的過程。

會發(fā)現(xiàn)不管是self、還是super指向消息接受者是一樣的,并且經(jīng)過消息傳遞,最終處理消息的方法都是NSObject中的- (Class)class方法。

參考文章:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,042評論 0 9
  • 從小就喜歡綠色,深深淺淺的綠,都喜歡! 喜歡綠色其實(shí)是有原因的。 綠色是好吃的 小時(shí)候,生活在農(nóng)村,村子里家家戶戶...
    常拓閱讀 908評論 0 5
  • 隨喜贊嘆自己堅(jiān)持新一天的咖啡冥想,而且不遲交。 我想要實(shí)現(xiàn)財(cái)富自由,月收入達(dá)到6000元。我為是時(shí)候給種下的好種子...
    極致踐行燕燕閱讀 171評論 0 0
  • 如果你是網(wǎng)民,這兩天應(yīng)該被以下三句話刷屏—— 微博里,“freestyle”、“吳亦凡freestyle”、“fr...
    索拉說閱讀 1,011評論 1 6

友情鏈接更多精彩內(nèi)容