前言
關(guān)于Objective-C Runtime一篇好的文檔 : Understanding the Objective-C Runtime
譯文地址為: http://blog.cocoabit.com/blog/2014/10/06/yi-li-jieobjective-cruntime/
Objective-C Runtime源碼是開(kāi)源的,下載地址為: http://opensource.apple.com/tarballs/objc4/
習(xí)題內(nèi)容
唐巧_boy在微博上分享了他們技術(shù)討論會(huì)關(guān)于objc runtime的討論習(xí)題內(nèi)容,習(xí)題來(lái)自 sunnyxx, 他的博客地址為 http://blog.sunnyxx.com。
以下是習(xí)題內(nèi)容(圖片轉(zhuǎn)自@唐巧_boy微博):

自己做完這些題之后,也順便復(fù)習(xí)了一些Objective-C Runtime的知識(shí),現(xiàn)在整理一下,分享給大家。
刨根問(wèn)底
下面的代碼輸出什么?
@implementation Son : Father
- (id)init
{
self = [super init];
if (self)
{
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
}
return self;
}
@end
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([super class]) = Son
解惑:這個(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。