刨根問底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。