ObjC Runtime簡析 -- super和superclass
這一個經典的面試題,Student是Person的一個子類,在子類Student的init方法中呼叫4個方法並列印結果。

objc_msgSend(self, sel_registerName("class")) objc_msgSend(self, sel_registerName("superclass")) objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class")) objc_msgSendSuper({(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("superclass"))
將這個 Student.m
轉換為cpp檔案檢視其底層的方法呼叫的到如下呼叫:
[self class]: objc_msgSend(self, sel_registerName("class")) [self superclass]: objc_msgSend(self, sel_registerName("superclass")) [super class]: objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class")) [super superclass]: objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("superclass")) 複製程式碼
我們看到當對self進行訊息傳送的時候底層是呼叫了runtime的 objc_msgSend
方法,而對super進行訊息傳送的時候底層是呼叫了 objc_getSuperClass
。
objc_msgSend
方法我們都熟悉了,將會從self開始查詢 class
方法和 superclass
方法的實現,呼叫列印Student和Person。
而對super傳送訊息,底層將會呼叫 objc_msgSendSuper
函式,這個函式有兩個引數,第一個是一個結構,第二個是方法選擇器。結構體有兩個成員:

第一個是訊息接受者,第二個引數我們通過註釋可以看出,表示函式從哪裡開始查詢法方法。而這裡傳遞的是 class_getSuperclass(objc_getClass("Student"))
表示Student的父類,也就是Person類開始查詢方法。查詢的方法是 class
和 superclass
,而這兩個方法存在於 NSObject
中,查詢到了之後依然使用 objc_msgSendSuper
第一個引數結構體的第一個成員接收訊息。訊息接受者是 self
,所以依然呼叫 self
的 class
方法和 superclass
。
所以最終 [super class]
和 [super superclass]
列印的依然是Student和Person。
總結
對super發訊息底層呼叫的是 objc_msgSendSuper
方法,它有兩個引數,第一個是一個結構,第二個是方法選擇器。本質上所做的操作是從當前類的父類開始查詢方法,而訊息的接受者依然是self,也就是當前類,所以最後還是 [self xxxx]
。