self 和 Super

刨根問底Objective-C Runtime(1)- Self & Super

下面的代碼輸出什么?

@implementation?Son?:?Father

-?(id)init

{

? ? self?=?[superinit];

? ? if(self)

? ? {

????????NSLog(@"%@",?NSStringFromClass([self?class]));

????????NSLog(@"%@",?NSStringFromClass([superclass]));

????}

????returnself;

}

@end

答案:都輸出 Son


2014-11-05?11:06:18.060?Test[8566:568584]?NSStringFromClass([self?class])?=?Son

2014-11-05?11:06:18.061?Test[8566:568584]?NSStringFromClass([superclass])?=?Son

解惑:這個題目主要是考察關(guān)于objc中對 self 和 super 的理解。

self 是類的隱藏參數(shù),指向當前調(diào)用方法的這個類的實例。而 super 是一個 Magic Keyword, 它本質(zhì)是一個編譯器標示符,和 self 是指向的同一個消息接受者。上面的例子不管調(diào)用[self class]還是[super class],接受消息的對象都是當前 Son *xxx 這個對象。而不同的是,super是告訴編譯器,調(diào)用 class 這個方法時,要去父類的方法,而不是本類里的。

當使用 self 調(diào)用方法時,會從當前類的方法列表中開始找,如果沒有,就從父類中再找;而當使用 super 時,則從父類的方法列表中開始找。然后調(diào)用父類的這個方法。

真的是這樣嗎?繼續(xù)看:

使用clang重寫命令:

1$?clang?-rewrite-objc?test.m

發(fā)現(xiàn)上述代碼被轉(zhuǎn)化為:NSLog((NSString?*)&__NSConstantStringImpl__var_folders_gm_0jk35cwn1d3326x0061qym280000gn_T_main_a5cecc_mi_0,?NSStringFromClass(((Class?(*)(id,?SEL))(void?*)objc_msgSend)((id)self,?sel_registerName("class"))));

NSLog((NSString?*)&__NSConstantStringImpl__var_folders_gm_0jk35cwn1d3326x0061qym280000gn_T_main_a5cecc_mi_1,?NSStringFromClass(((Class?(*)(__rw_objc_super?*,?SEL))(void?*)objc_msgSendSuper)((__rw_objc_super){?(id)self,?(id)class_getSuperclass(objc_getClass("Son"))?},?sel_registerName("class"))));

從上面的代碼中,我們可以發(fā)現(xiàn)在調(diào)用 [self class] 時,會轉(zhuǎn)化成 objc_msgSend函數(shù)。看下函數(shù)定義:

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

我們把 self 做為第一個參數(shù)傳遞進去。

而在調(diào)用 [super class]時,會轉(zhuǎn)化成 objc_msgSendSuper函數(shù)。看下函數(shù)定義:

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

第一個參數(shù)是 objc_super 這樣一個結(jié)構(gòu)體,其定義如下:

struct?objc_super?{

???__unsafe_unretained?id?receiver;

???__unsafe_unretained?Class?super_class;

};

結(jié)構(gòu)體有兩個成員,第一個成員是 receiver, 類似于上面的 objc_msgSend函數(shù)第一個參數(shù)self 。第二個成員是記錄當前類的父類是什么。

所以,當調(diào)用 [self class] 時,實際先調(diào)用的是 objc_msgSend函數(shù),第一個參數(shù)是 Son當前的這個實例,然后在 Son 這個類里面去找 - (Class)class這個方法,沒有,去父類 Father里找,也沒有,最后在 NSObject類中發(fā)現(xiàn)這個方法。而 - (Class)class的實現(xiàn)就是返回self的類別,故上述輸出結(jié)果為 Son。

objc Runtime開源代碼對- (Class)class方法的實現(xiàn):

-?(Class)class?{

????returnobject_getClass(self);

}

而當調(diào)用 [super class]時,會轉(zhuǎn)換成objc_msgSendSuper函數(shù)。第一步先構(gòu)造 objc_super 結(jié)構(gòu)體,結(jié)構(gòu)體第一個成員就是 self 。第二個成員是 (id)class_getSuperclass(objc_getClass(“Son”)) , 實際該函數(shù)輸出結(jié)果為 Father。第二步是去 Father這個類里去找- (Class)class,沒有,然后去NSObject類去找,找到了。最后內(nèi)部是使用 objc_msgSend(objc_super->receiver, @selector(class))去調(diào)用,此時已經(jīng)和[self class]調(diào)用相同了,故上述輸出結(jié)果仍然返回 Son。

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

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

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