Objective-C self super

來源:互聯網
上載者:User

標籤:

題目

上題目,已知A是爺爺,B是爸爸,C是孫子。

@interface A : NSObject- (void)f;@end@interface B : A- (void)f;- (void)g;@end@interface C : B- (void)f;@end

A,B,C都各自實現了函數f,只有B實現了函數g。

@implementation A- (void)f{    NSLog(@"A");}@end@implementation B- (void)f{    NSLog(@"B");}- (void)g{    [self f];    [super f];    NSLog(@"%@", [self class]);    NSLog(@"%@", [super class]);}@end@implementation C- (void)f{    NSLog(@"C");}@end

請問,下面代碼輸出什嗎?

C *c = [[C alloc] init];[c g];

 

 

 

 

 

 

答案是CACC.

分析

1.C中沒有g,為什麼可以調用B的方法

C繼承自B,所以C中雖然沒有g方法,但是會去從下往上找,找打B類的g方法進行調用。

 

2.關於[self f]

調用B的g的過程中,self其實C,因為此時函數g訊息的接受者是c。所以系統從self的類(即C)開始從下往上找,因為C中實現了f,所以直接輸出C。

 

3.關於[super f]

這個問題是最困惑我的,臥槽,居然輸出的是A而不是B?!

首先要明確的一點是,self和super不是同一個層面上的東西。

 

self是什嗎?

self 是類的隱藏的參數,指向當前當前調用方法的類,另一個隱藏參數是 _cmd,代表當前類方法的 selector。

 

super是什嗎?

super可不是想象中的self.superclass啊

super是Objective-C的文法糖,是一個編譯器指示符,像宏一樣,運行時XCode可不認識super這個東西。

 

其實Objective-C的函數調用的本質是

id objc_msgSend(id theReceiver, SEL op, ...)

省略符號表示不定參數。

即[self f]的本質是 objc_msgSend(self, f, "");

所以,這點跟C++不同,並不是self去調用了函數f,而是訊息f發送給了self,self是訊息接受者。正是因為這樣,Objective-C中[nil f]這種寫法沒問題,因為發送給nil的任何訊息都返回nil。

objc_msgSend(theReceiver, op, ...)的本質是,從theReceiver所在的類開始找,不斷往上找,看看哪個類實現了op,一旦找到則將訊息發送給它處理。

 

但是[super f] 可不就是這樣了,[super f]本質是

id objc_msgSendSuper(struct objc_super *super, SEL op, ...)

省略符號表示不定參數。

即[self f]的本質是 objc_msgSendSuper(super, f, "");

 

objc_super何許人也?

struct objc_super {   __unsafe_unretained id receiver;   __unsafe_unretained Class super_class;};

objc_super的receiver是什嗎?

reveiver是當前訊息的接受者,代碼裡寫的是[c g],所以super的receiver就是C.你也可以理解為就是self。

objc_super的super_class是什嗎?

super_class是當前super所在代碼的類的父類,很繞口,但是這句一定要好好理解。比如無論誰調用了g,是C也好是B也罷,g中[super f]的super的super_class一定是A,因為super這5個字母是寫在B裡面的。

 

objc_msgSendSuper(super, op, ...)的本質是,從super_class->super_class所在的類開始找,不斷往上找,看看哪個類實現了op,一旦找到了則將訊息發送給它處理。

 

在編譯的時候,編譯器看到了super,會因此構造一個struct。objc_super->receiver填了C,objc_super->super_class填了A。因此運行時編譯器變不認識了super。

 

如果你已經清楚了上面的邏輯,請回頭看看[super f]。

[super f],super->reveiver是C,super->super_class是A。所以從A開始找f,找到了則系統可能這樣調用

objc_msgSend(super->recevier, f, nil)  //此時f是已經找到了的f,即A的f

 

4.關於[self class]

首先非常有必要看看class的實現,參考自蘋果RunTime開原始碼

- (Class)class {    return object_getClass(self);}

 

可以看到class返回的是self的類名。

好,繼續,[self class]中,class也是一個訊息,接受者是self,也就是C,所以系統從C開始找class函數的實現,沒找到,找B,找A都找不到,到了NSObjcect這一層找到了。

此時調用了NSObject的class方法,那此時self是C,那就返回了C。

 

5.關於[super class]

這個問題一開始看起來也很奇怪,居然[self class]和[super class]輸出了同一個東西,這不科學啊。但是把上面的知識理解好了,也就不奇怪了。

執行[super class]時,編譯器將[super class]替換為

objc_msgSendSuper(super, class, nil)

其中super為reveiver=C,superclass=A。

系統從A開始找class,找不到,到了NSObject這一層找到了。

那麼系統可能這樣調用

objc_msgSend(objc_super->receiver, class, nil)  //此時class是已經找到了的class,即NSObject的class

此時調用了NSObject的class方法,那此時self是C,那就返回了C。

 

總結

道理懂了之後就是思考的效率問題了,凡是self的就從訊息接受者的類開始從下往上找;凡是super的就從寫super的這個類開始往上找。

 

參考連結

《刨根問底Objective-C Runtime(1)- Self & Super》

《Objective-C 中Self 和 Super 詳解》

《蘋果RunTime開原始碼》

《Objective-C Super的理解》

Objective-C self super

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.