Objective-C中的類和元類

你真的知道OC的類(Class)是個什么玩意兒?

眾所周知,所有的對象都是由其對應的類實例化而來,但是類本身其實也是一種對象,surprise?下面我們就來撥開這層迷霧。

在Objective-C中,我們用到的幾乎所有類都是NSObject類的子類,查閱objc源碼你會發(fā)現(xiàn) NSObject類定義(如圖1)我們這里只給出定義其他方法大家自行查閱。


圖1


看完這個,那么問題來了:這個Class 類型的 isa 是個什么玩意兒?Class 又是個什么類型?帶著這兩個疑問我們查閱一下objc.h中Class 的定義(如圖2)

圖2

看完這個是不是又一臉懵逼!Class 被定義為一個指向objc_class 的結構體指針。那么objc_class 又是個什么玩意兒?我們接著看源碼runtime.h中定義(如圖3)

圖3

你會發(fā)現(xiàn),我艸,怎么又一個isa! 下面我們來解答這個疑惑。

其實在Objective-C中任何的類定義都是對象。即在程序啟動的時候任何類定義都對應于一塊內(nèi)存。在編譯的時候,編譯器會給每一個類生成一個且只生成一個”描述其定義的對象”,也就是蘋果公司說的類對象(class object),他是一個單例(singleton), 而我們在其他面向?qū)ο笳Z言中所謂的對象,叫做實例對象(instance object)。對于實例對象我們不難理解,但類對象(class object)是個什么鬼?我們知道Objective-C是門很動態(tài)的語言,因此程序里的所有實例對象(instace object)都是在運行時由Objective-C的運行時庫生成的,而這個類對象(class object)就是運行時庫用來創(chuàng)建實例對象(instance object)的依據(jù)。

通過上面的討論,可以得出結論,不管是實例對象,類對象,其結構中都有一個isa。實例對象中的isa 指針指向的是 該實例的類對象,那么同理,類對象的isa 指向的是誰呢?這就是 元類對象(meta class object)。他們之間的關系看起來是這樣的(如圖4):

圖4

類對象

類對象的本質(zhì)

通過前文我們了解到,類對象是編譯器生成的“描述類定義的對象”,就是在編譯時的類。任何直接或者間接繼承NSObject的類,它的實例對象(instance object)中都有一個isa 指針,指向它的類對象(class object)。這個類對象(class object)中存儲了關于這個實例對象(instace object)所屬的類的定義的一切:包括變量,方法,遵守的協(xié)議等等,這個可以通過(圖3)來佐證。因此,類對象能訪問所有關于這個類的信息,利用這些信息可以產(chǎn)生一個新的實例,但是類對象不能訪問任何實例對象的內(nèi)容。當你調(diào)用一個 “類方法” 例如 [NSObject alloc],你事實上是發(fā)送了一個消息給他的類對象。所謂一切皆對象就是這個意思。

那么類對象與實例對象有什么區(qū)別呢?

盡管類對象保留了一個類實例的原型,但它并不是實例本身。它沒有自己的實例變量,也不能執(zhí)行那些類的實例的方法(只有實例對象才可以執(zhí)行實例方法)。然而,類的定義能包含那些特意為類對象準備的方法–類方法( 而不是的實例方法)。類對象從父類那里繼承類方法,就像實例從父類那里繼承實例方法一樣。

類對象是不是就是類名?

只有在消息表達式中作為接收者,類名才代表類對象。我理解為調(diào)用靜態(tài)方法的時候。

元類對象

元類對象的實質(zhì)

實際上,類對象是元類對象的一個實例。元類描述了 一個類對象,就像類對象描述了普通對象一樣。不同的是元類的方法列表是類方法的集合,由類對象的選擇器來響應。當向一個類發(fā)送消息時,objc_msgSend會通過類對象的isa指針定位到元類,并檢查元類的方法列表(包括父類)來決定調(diào)用哪個方法。元類代替了類對象描述了類方法,就像類對象代替了實例對象描述了實例化方法一樣。

很顯然,元類也是對象,也應該是其他類的實例,實際上元類是根元類(root class’s metaclass)的實例,而根元類是其自身的實例,即根元類的isa指針指向自身。

類的super_class指向其父類,而元類的super_class則指向父類的元類。元類的super class鏈與類的super class鏈平行,所以類方法的繼承與實例方法的繼承也是并行的。而根元類(root class’s metaclass)的super_class指向根類(root class),這樣,整個isa指針鏈就是一個閉環(huán)。

記住,當一個消息發(fā)送給任何一個對象, 方法的檢查 從對象的 isa 指針開始,然后是父類。實例方法在類中定義, 類方法 在元類和根類中定義。(根類的元類就是根類自己)。在一些計算機語言的原理中,一個類和元類層次結構可以更自由的組成,更深元類鏈和從單一的元類繼承的更多的實例化的類。Objective-C 的類方法 是使用元類的根本原因,在其他方面試圖在隱藏元類。例如 [NSObject class] 完全相等于 [NSObject self],所以,在形式上他還是返回的 NSObject->isa 指向的元類。 Objective-C語言是一組實用的折中方案。下圖表示了對象間的isa的關系,以及類的繼承關系:

圖片來自網(wǎng)絡(圖5)


綜上所述,類對象(class object)中包含了類的實例變量,實例方法的定義,而元類對象(metaclass object)中包括了類的類方法(也就是C++中的靜態(tài)方法)的定義。類對象和元類對象中當然還會包含一些其它的東西,蘋果以后也可能添加其它的內(nèi)容,但對于我們只需要記住:類對象存的是關于實例對象的信息(變量,實例方法等),而元類對象(metaclass object)中存儲的是關于類的信息(類的版本,名字,類方法等)。要注意的是,類對象(class object)和元類對象(metaclass object)的定義都是objc_class結構,其不同僅僅是在用途上,比如其中的方法列表在類對象(instance object)中保存的是實例方法(instance method),而在元類對象(metaclass object)中則保存的是類方法(class method)。

寫了這么多不知道能夠撥開您心中的迷霧呢?歡迎大家勘誤,互相學習!

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

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

  • 轉(zhuǎn)至元數(shù)據(jù)結尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 2,049評論 0 9
  • 首先說明,這篇文章幾乎都是抄錄的別人的博客,簡書文章,在此總結,只是為了方便記憶和以后閱讀,如果有什么失禮的地方,...
    LiYaoPeng閱讀 5,339評論 1 14
  • 原文出處:南峰子的技術博客 Objective-C語言是一門動態(tài)語言,它將很多靜態(tài)語言在編譯和鏈接時期做的事放到了...
    _燴面_閱讀 1,415評論 1 5
  • 本文轉(zhuǎn)載自:http://southpeak.github.io/2014/10/25/objective-c-r...
    idiot_lin閱讀 1,028評論 0 4
  • 我們常常會聽說 Objective-C 是一門動態(tài)語言,那么這個「動態(tài)」表現(xiàn)在哪呢?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,333評論 0 7

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