下面的代碼輸出什么蹄衷?
@implementation Son : Father
- (id)init
{
self = [``super
init];
if
(self) {
NSLog(@``"%@"``, NSStringFromClass([self class]));
NSLog(@``"%@"``, NSStringFromClass([``super
class]));
}
return
self;
}
@end
答案:都輸出 Son
NSStringFromClass([self class]) = Son
NSStringFromClass([``super
class]) = Son
解惑:
(以下解惑部分摘自微博@Chun_iOS的博文刨根問(wèn)底Objective-C Runtime(1)- Self & Super)
這個(gè)題目主要是考察關(guān)于objc中對(duì) self 和 super 的理解若贮。
self 是類(lèi)的隱藏參數(shù)捏肢,指向當(dāng)前調(diào)用方法的這個(gè)類(lèi)的實(shí)例。而 super 是一個(gè) Magic Keyword, 它本質(zhì)是一個(gè)編譯器標(biāo)示符,和 self 是指向的同一個(gè)消息接受者钞螟。
上面的例子不管調(diào)用[self class]還是[super class],接受消息的對(duì)象都是當(dāng)前 Son *xxx 這個(gè)對(duì)象谎碍。而不同的是鳞滨,super是告訴編譯器,調(diào)用 class 這個(gè)方法時(shí)蟆淀,要去父類(lèi)的方法拯啦,而不是本類(lèi)里的。
當(dāng)使用 self 調(diào)用方法時(shí)熔任,會(huì)從當(dāng)前類(lèi)的方法列表中開(kāi)始找褒链,如果沒(méi)有,就從父類(lèi)中再找疑苔;而當(dāng)使用 super 時(shí)甫匹,則從父類(lèi)的方法列表中開(kāi)始找。然后調(diào)用父類(lèi)的這個(gè)方法惦费。
真的是這樣嗎兵迅?繼續(xù)看:
使用clang重寫(xiě)命令:
$ 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] 時(shí)薪贫,會(huì)轉(zhuǎn)化成 objc_msgSend函數(shù)喷兼。看下函數(shù)定義:
id objc_msgSend(id self, SEL op, ...)
我們把 self 做為第一個(gè)參數(shù)傳遞進(jìn)去后雷。
而在調(diào)用 [super class]時(shí),會(huì)轉(zhuǎn)化成 objc_msgSendSuper函數(shù)吠各⊥瓮唬看下函數(shù)定義:
id objc_msgSendSuper(struct objc_super *``super``, SEL op, ...)
第一個(gè)參數(shù)是 objc_super 這樣一個(gè)結(jié)構(gòu)體,其定義如下:
struct objc_super {
__unsafe_unretained id receiver;
__unsafe_unretained Class super_class;
};
結(jié)構(gòu)體有兩個(gè)成員贾漏,第一個(gè)成員是 receiver, 類(lèi)似于上面的 objc_msgSend函數(shù)第一個(gè)參數(shù)self 候学。第二個(gè)成員是記錄當(dāng)前類(lèi)的父類(lèi)是什么。
所以纵散,當(dāng)調(diào)用 [self class] 時(shí)梳码,實(shí)際先調(diào)用的是 objc_msgSend函數(shù)隐圾,第一個(gè)參數(shù)是 Son當(dāng)前的這個(gè)實(shí)例,然后在 Son 這個(gè)類(lèi)里面去找 - (Class)class這個(gè)方法掰茶,沒(méi)有暇藏,去父類(lèi) Father里找,也沒(méi)有濒蒋,最后在 NSObject類(lèi)中發(fā)現(xiàn)這個(gè)方法盐碱。而 - (Class)class的實(shí)現(xiàn)就是返回self的類(lèi)別,故上述輸出結(jié)果為 Son沪伙。
objc Runtime開(kāi)源代碼對(duì)- (Class)class方法的實(shí)現(xiàn):
- (Class)class {
return
object_getClass(self);
}
而當(dāng)調(diào)用 [super class]時(shí)瓮顽,會(huì)轉(zhuǎn)換成objc_msgSendSuper函數(shù)。第一步先構(gòu)造 objc_super 結(jié)構(gòu)體围橡,結(jié)構(gòu)體第一個(gè)成員就是 self 暖混。 第二個(gè)成員是 (id)class_getSuperclass(objc_getClass(“Son”)) , 實(shí)際該函數(shù)輸出結(jié)果為 Father。 第二步是去 Father這個(gè)類(lèi)里去找 - (Class)class翁授,沒(méi)有拣播,然后去NSObject類(lèi)去找,找到了黔漂。最后內(nèi)部是使用 objc_msgSend(objc_super->receiver, @selector(class))去調(diào)用诫尽, 此時(shí)已經(jīng)和[self class]調(diào)用相同了,故上述輸出結(jié)果仍然返回 Son炬守。