iOS經(jīng)典講解之[self class]和[super class]的區(qū)別

作者:Loving_iOS

轉(zhuǎn)載請標(biāo)明出處:http://blog.csdn.net/loving_ios/article/details/49884599

在objc中的類實現(xiàn)中經(jīng)??吹竭@兩個關(guān)鍵字”self”和”super”,但他們的區(qū)別表現(xiàn)在各個方面。

以下面的代碼為例:

[objc]?view plain?copy

```

@interface?Father:NSObject???

{??

NSString*??name;??

}??

-?(void)setName:(NSString*)?yourName;??


@end??


@interface?Son:Father??

{??

NSUInteger?age;??

}??

-?(void)?setAge:(NSUInteger)?age;??

-?(void)?setName:(NSString*)?yourName?andAge:(NSUInteger)?age;??

@end??

@implementation?Son??

-?(void)?setName:(NSString*)?yourName?andAge:(NSUInteger)?age???

{??

[self?setAge:age];??

[super?setName:yourName];??

}??

@end??

int?main(int?argc,?char*?argv[])?{??

AutoreleasePool{??

Son*?son?=?[[Son?alloc]?init];??

[son?setName:@"aaa"?andAge:18];??


}??

return?0;??

}??

```

上面有簡單的兩個類,在子類Son中調(diào)用了自己類中的setAge和父類中的setName,這些代碼看起來很好理解,沒什么問題。 然后我在setName:andAge的方法中加入兩行:

```

NSLog(@"self ' class is %@", [self class]);

NSLog(@"super' class is %@", [super class]);

```

這樣在調(diào)用時,會打出來這兩個的class,先猜下吧,會打印出什么? 按照以前oop語言的經(jīng)驗,這里應(yīng)該會輸出: self ' s class is Son super ' s class is Father

但是編譯運行后,可以發(fā)現(xiàn)結(jié)果是:

```

self 's class is Son

super ' s class is Son

```

self的class和預(yù)想的一樣,怎么super的class也是Son?

具體原因要看他們的內(nèi)部實現(xiàn)機制是什么樣的:

self 是類的隱藏的參數(shù),指向當(dāng)前當(dāng)前調(diào)用方法的類,另一個隱藏參數(shù)是_cmd,代表當(dāng)前類方法的selector。這里只關(guān)注這個self。super是個 啥?super并不是隱藏的參數(shù),它只是一個“編譯器指示符”,它和self指向的是相同的消息接收者,拿上面的代碼為例,不論是用[self setName]還是[super setName],接收“setName”這個消息的接收者都是son這個對象。不同的是,super告訴編譯器,當(dāng)調(diào)用setName的方法時,要去調(diào)用父類的方法,而不是本類里的,super只是指示符的作用沒有實際意義。

當(dāng)使用self調(diào)用方法時,會從當(dāng)前類的方法列表中開始找,如果沒有,就從父類中再找;而當(dāng)使用super時,則從父類的方法列表中開始找。然后調(diào)用父類的這個方法。

這種機制到底底層是如何實現(xiàn)的?其實當(dāng)調(diào)用類方法的時候,編譯器會將方法調(diào)用轉(zhuǎn)成一個C函數(shù)方法調(diào)用,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’s perform… 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.

可以看到會轉(zhuǎn)成調(diào)用上面4個方法中的一個,由于_stret系列的和沒有_stret的那兩個類似,先只關(guān)注objc_msgSend和objc_msgSendSuper兩個方法。

當(dāng)使用[self setName]調(diào)用時,會使用objc_msgSend的函數(shù),先看下objc_msgSend的函數(shù)定義:

?id objc_msgSend(id theReceiver, SEL theSelector, ...)

第一個參數(shù)是消息接收者,第二個參數(shù)是調(diào)用的具體類方法的selector,后面是selector方法的可變參數(shù)。我們先不管這個可變參數(shù),以 [self setName:]為例,編譯器會替換成調(diào)用objc_msgSend的函數(shù)調(diào)用,其中theReceiver是self,theSelector是 @selector(setName:),這個selector是從當(dāng)前self的class的方法列表開始找的setName,當(dāng)找到后把對應(yīng)的 selector傳遞過去。

而當(dāng)使用[super setName]調(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)編譯器遇到Son里setName:andAge方法里的[super setName:]時,開始做這幾個事:

1,構(gòu)建objc_super的結(jié)構(gòu)體,此時這個結(jié)構(gòu)體的第一個成員變量receiver就是son,和self相同。而第二個成員變量superClass就是指類Father,因為Son的超類就是這個Father。

2,調(diào)用objc_msgSendSuper的方法,將這個結(jié)構(gòu)體和setName的sel傳遞過去。函數(shù)里面在做的事情類似這樣:從 objc_super結(jié)構(gòu)體指向的superClass的方法列表開始找setName的selector,找到后再以 objc_super->receiver去調(diào)用這個selector,可能也會使用objc_msgSend這個函數(shù),不過此時的第一個參數(shù) theReceiver就是objc_super->receiver,第二個參數(shù)是從objc_super->superClass中找到 的selector

里面的調(diào)用機制大體就是這樣了,以上面的分析,回過頭來看開始的代碼,當(dāng)輸出[self class]和[super class]時,是個怎樣的過程。

當(dāng)使用[self class]時,這時的self是Son,在使用objc_msgSend時,第一個參數(shù)是receiver也就是self,也是 Son* son這個實例。第二個參數(shù),要先找到class這個方法的selector,先從Son這個類開始找,沒有,然后到Son的父類 Father中去找,也沒有,再去Father的父類NSObject去找,一層一層向上找之后,在NSObject的類中發(fā)現(xiàn)這個class方法,而 NSObject的這個class方法,就是返回receiver的類別,所以這里輸出Son。

當(dāng)使用[super class]時,這時要轉(zhuǎn)換成objc_msgSendSuper的方法。先構(gòu)造objc_super的結(jié)構(gòu)體吧,第一個成員變量就是self, 第二個成員變量是Father,然后要找class這個selector,先去superClass也就是Father中去找,沒有,然后去Father 的父類中去找,結(jié)果還是在NSObject中找到了。然后內(nèi)部使用函數(shù)objc_msgSend(objc_super->receiver, @selector(class)) 去調(diào)用,此時已經(jīng)和我們用[self class]調(diào)用時相同了,此時的receiver還是Son* son,所以這里返回的也是Son。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,054評論 0 9
  • 在objc中的類實現(xiàn)中經(jīng)常看到這兩個關(guān)鍵字”self”和”super”,但他們的區(qū)別表現(xiàn)在各個方面。以下面的代碼為...
    woshishui1243閱讀 237評論 0 0
  • 一 “一個女孩子,那么努力干什么,學(xué)的好不如嫁的好?!?“你看誰誰誰,大專畢業(yè),找了一個富二代,現(xiàn)在在家做富太太呢...
    甜蜜醫(yī)僧閱讀 1,807評論 4 5
  • 當(dāng)我是一個人的時候, 我覺得我是世界上最好的人、 理應(yīng)遇到一個和我一樣好的人、 我們在一起、寫一段世界上最美麗的愛...
    cyyier閱讀 215評論 0 2
  • 一到了夏天,大東巷子“老陳”冷飲店的生意就開始好起來。 整條巷子包括附近巷子的街坊鄰居都喜歡在某個午睡后的時刻,男...
    二三小姐閱讀 247評論 0 1

友情鏈接更多精彩內(nèi)容