前提
面試的時候會不會問到類似的問題:類ClassB繼承于類ClassA,這時候在類ClassB的方法中分別打印[self class] 與 [super class]會輸出什么?
實踐出真知:
有沒有被驚艷到?[super class]不應(yīng)該是ClassA嗎?請往下看
Self關(guān)鍵字與Super關(guān)鍵字
????self 是類的隱藏的參數(shù),指向當(dāng)前調(diào)用方法的類,另一個隱藏參數(shù)是_cmd,代表當(dāng)前類方法的selector。這里只關(guān)注這個self。
????super并不是隱藏的參數(shù),它只是一個“編譯器指示符”,它和self指向的是相同的消息接收者。不同的是,super告訴編譯器,要去調(diào)用父類的方法而不是本類里的,super只是指示符的作用沒有實際意義。
????當(dāng)使用self調(diào)用方法時,會從當(dāng)前類的方法列表中開始找,如果沒有,就從父類中再找;而當(dāng)使用super時,則從父類的方法列表中開始找。然后調(diào)用父類的這個方法。
實現(xiàn)機制
apple的objcRuntimeRef 上說:
Sending Messages
When it encounters a method invocation, the compiler might generate a call to any of several functions to perform the actual message dispatch, depending on the receiver, the return value, and the arguments. You can use these functions to dynamically invoke methods from your own plain C code, or to use argument forms not permitted by NSObject’sperform...methods. These functions are declared in/usr/include/objc/objc-runtime.h.
objc_msgSend?sends a message with a simple return value to an instance of a class.
objc_msgSend_stret?sends a message with a data-structure return value to an instance of a class.
objc_msgSendSuper?sends a message with a simple return value to the superclass of an instance of a class.
objc_msgSendSuper_stret?sends a message with a data-structure return value to the superclass of an instance of a class.
我們只關(guān)注objc_msgSend和objc_msgSendSuper兩個方法。
當(dāng)使用[self class]調(diào)用時,會使用objc_msgSend的函數(shù),先看下objc_msgSend的函數(shù)定義:
id objc_msgSend(id theReceiver, SEL theSelector, ...)
第一個參數(shù)是消息接收者,第二個參數(shù)是調(diào)用的具體類方法的selector,后面是selector方法的可變參數(shù)。
以 [self class]為例,編譯器會替換成調(diào)用objc_msgSend的函數(shù)調(diào)用,其中theReceiver是self,theSelector是 @selector(class),這個selector是從當(dāng)前self的class的方法列表開始找的@selector(class),當(dāng)找到后把對應(yīng)的 selector傳遞過去。
而當(dāng)使用[super class]調(diào)用時,會使用objc_msgSendSuper函數(shù),看下objc_msgSendSuper的函數(shù)定義:
id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
第一個參數(shù)是個objc_super的結(jié)構(gòu)體,第二個參數(shù)還是類似上面的類方法的selector,先看下objc_super這個結(jié)構(gòu)體是什么東西:
struct objc_super {
id receiver;
Class superClass;
};
可以看到這個結(jié)構(gòu)體包含了兩個成員,一個是receiver,這個類似上面objc_msgSend的第一個參數(shù)receiver,第二個成員是記 錄寫super這個類的父類是什么
拿上面的代碼為例,當(dāng)編譯器遇到ClassB中init方法里的[super class]時,開始做這幾個事:
1,構(gòu)建objc_super的結(jié)構(gòu)體,此時這個結(jié)構(gòu)體的第一個成員變量receiver就是ClassB的實例,和self相同。而第二個成員變量superClass就是指類ClassA,因為ClassB的超類就是這個ClassA。
2,調(diào)用objc_msgSendSuper的方法,將這個結(jié)構(gòu)體和class方法傳遞過去。函數(shù)里面在做的事情類似這樣:從 objc_super結(jié)構(gòu)體指向的superClass的方法列表開始找class的selector,找到后再以 objc_super->receiver去調(diào)用這個selector,可能也會使用objc_msgSend這個函數(shù),不過此時的第一個參數(shù) theReceiver就是objc_super->receiver,第二個參數(shù)是從objc_super->superClass中找到的selector,源代碼匯編核心代碼大概是這個意思
ENTRY _objc_msgSendSuper
MESSENGER_START
ldr r9, [r0, #CLASS] // r9 = struct super->class
CacheLookup NORMAL
// cache hit, IMP in r12, eq already set for nonstret forwarding
ldr r0, [r0, #RECEIVER] // load real receiver?在這里直接加載真實的receiver
MESSENGER_END_FAST
bx r12 // call imp
CacheLookup2 NORMAL
// cache miss
ldr r9, [r0, #CLASS] // r9 = struct super->class
ldr r0, [r0, #RECEIVER] // load real receiver ?在這里直接加載真實的receiver
MESSENGER_END_SLOW
b __objc_msgSend_uncached
END_ENTRY _objc_msgSendSuper
里面的調(diào)用機制大體就是這樣了
由此可以知道,為什么[self class]與[super class]打印結(jié)果相同了吧
參考內(nèi)容:
Apple 之《objc4 》
南峰子的技術(shù)博客之《Objective-C Runtime 運行時之一:類與對象 》
Loving_iOS之《iOS經(jīng)典講解之[self class]和[super class]的區(qū)別 》
GSChan之《iOS中self與super 》