Objective-C的物件模型與執行時

發表於2014-12-19

本人blog的前一篇文章從Objective-C的訊息傳送角度整理了執行時的相關內容,本篇文章我們就來從資料結構方面分析下為什麼Objective-C可以擁有訊息傳送中的這些特點,進一步剖析下Objective-C的執行時。

0. Objective-C與C

從Objective-C的名字上我們就能看出來它和C語言有著很密切的關係,是“物件導向的C語言”。Objective-C誕生於上世紀80年代,那個時候物件導向的理念已經得到了初步發展,C語言當時也已經是很成熟的語言。和C++類似,Objective-C也在C語言的基礎上,增添了物件導向的特性。同是在1983年前後出現,Objective-C和C++在對C語言的物件導向特性擴充套件上,走出了不同的道路。

Objective-C語言的實現用到了一個用C語言寫的執行時系統,也就是一個動態連結庫——libobjc.A.dylib。這個動態庫裡面提供了Objective-C語言所需的各種動態特性,包括支援物件導向的一些特性。而Objective-C的編譯器可以以C編譯器為基礎,對Objective-C的語法做“預處理”擴充套件(GCC裡的Objective-C編譯器就是這麼做的)。

所以可以說Objective-C是以C語言為基礎,通過引入特有的執行時庫,形成一門支援物件導向特性的語言。

1. Objective-C目標檔案中的執行時資訊

前一篇文章中,我們通過一段示例程式碼演示了執行時對物件導向中多型特性的支援。一個訊息傳送語句會根據執行時的資訊判斷,具體應該呼叫哪個函式實現(比如區分父類還是子類)。而這些執行時所需要的資訊最終又是開發人員在寫程式碼時就新增進去的,其中蘊含著特定的邏輯。

其實,可以說不僅僅是Objective-C,絕大多數面嚮物件語言都是類似的。想要支援執行時多型,程式碼中一定包含有執行時所需的判斷資料,而且經過編譯器編譯過後一定會保留下來。只有這樣,機器在執行時才能有所依據。

像Java的JVM,在執行時為Java程式提供了強大的支援,而Java的執行時資訊都在.class檔案中按規範格式保留下來。編譯後的C++程式碼也一樣保有RTTI。

不像Java的虛擬機器那樣重,能夠支援python等其它語言生成的class。Objective-C的執行時針對Objective-C語言,更加短小精悍、簡單實用。而Objective-C程式碼中的執行時資訊都保留在編譯過後的目標檔案中(.o)。

實用Objective-C的編譯器編譯.m檔案之後,我們會看到生成有.o目標檔案,目標檔案中包含頭部、載入指令和各個段。其中有一個segment專門負責保留Objective-C的執行時資訊。

比如,實用otool,我們可以看到其中的內容:

如上圖中所示,這個.o目標檔案中包含了一個類(class)和一個元類(meta class)的資訊。這其中包括例項的大小、類名、父類、方法列表即使地址、protocal起始地址等。

如果,你和我一樣,之前做過Java,並且對Java的class檔案格式很感興趣,那麼現在你會發現,這個目標檔案中包含的Objective-C執行時資訊和class中的資料內容極為相似。

是的,技術方案是互通的,是相似的,相信其他很多物件導向的語言也有類似的方式。

2. 物件模型

剛剛提到了類和元類,這些是什麼? 在Objective-C中一個物件又是怎樣的實現? 什麼是物件? 相信讀完本段對Objective-C物件模型的介紹,如上問題就會自然解開了。

首先我們相信,無論是類還是物件,在最終的實現中都是一種資料結構,這點應該沒什麼好質疑的。

我們來看看Objective-C的物件是個什麼東西?

從objc.h中的如上程式碼來看,Objective-C的物件就是一個包含isa指標的資料結構,而isa又是一個Class型別的,Class則是一個名為objc_class的資料結構定義。

再看runtime.h中對objc_class的定義:

其中也是一個包含isa的結構。咦!那objc_object和objc_class不就一樣了?實際上看到這裡,的確就是這樣。

當然,一個實際的類,裡面還會包含各個變數成員,所以類定義好了,category也不能直接增加變數儲存。而這個isa就指向這個物件的實際類(isa指向一個“類物件”)。正是因為這樣,執行時一個訊息傳送才知道具體應該呼叫哪個方法實現。同時,一個類又包含了這個類的所有資訊(在“類物件”結構中記載)。這個“類物件”的isa指向元類(meta class)物件。“類物件”中有方法列表,這裡面的方法是例項方法(減號“-”方法),而“元類物件”中的方法列表則是類方法(加號“+”方法)。

我們來看張物件的圖:

有沒有覺得這個結構很熟悉? 沒錯,其實debug的時候都能看到,只是不是以影象的形式展現出來而已。

而關於“類”和“元類”,我們再看另一張圖:


Objective-C物件模型結構關係圖

看完上面這張Objective-C物件模型的關係圖,似乎一切就都清楚了!

就整理到此,希望能夠幫助各位朋友們讀懂Objective-C執行時中的奧祕。

參考:

相關文章