【iOS】類的本質與isa指標

weixin_34337265發表於2017-08-26
  • 類本身也是一個物件,是class型別的物件.
5239428-2fa370f831dfea52.png
效果圖1
5239428-c7a3f6aac093f812.png
效果圖2

objc_class結構體的定義:

假設我們建立一個Person類:

建立p物件:Person * p = [Person new] ;

在建立一個物件p之前,在堆記憶體中就先存在了一個該類(Person)的型別物件(類物件),類物件在編繹時系統會為我們自動建立。
建立一個物件之後,在堆記憶體中會建立了一個p物件,該物件包含了一個isa指標的成員變數(第一個屬性),isa指標則指向在堆裡面存在的類物件, 在棧記憶體裡建立了一個該類的指標p,p指標指向的是isa地址,isa指向Person.

圖1所示,Class是一個指向objc_class(類)結構體的指標,而id是一個指向objc_object(物件)結構體的指標。objec_object(物件)中isa指標指向的類結構稱為objec_class(該物件的類),其中存放著普通成員變數與物件方法 (“-”開頭的方法)。objec_class(類)中isa指標指向的類結構稱為metaclass(該類的元類),其中存放著static型別的成員變數與static型別的方法 (“+”開頭的方法)。

類物件(class object)

  • 類物件的實質由編譯器建立的,即在編譯時所謂的類,就是指類物件(官方文件中是這樣說的: The class object is the compiled version of the class)。任何直接或間接繼承了NSObject的類,它的例項物件(instance objec)中都有一個isa指標,指向它的類物件(class object)。這個類物件(class object)中儲存了關於這個例項物件(instace object)所屬的類的定義的一切:包括變數,方法,遵守的協議等等。因此,類物件能訪問所有關於這個類的資訊,利用這些資訊可以產生一個新的例項,但是類物件不能訪問任何例項物件的內容。當你呼叫一個 “類方法” 例如 [NSObject alloc],你事實上是傳送了一個訊息給他的類物件。
  • 類物件和例項物件是有很大區別的,儘管類物件保留了一個類例項的原型,但它並不是例項本身。它沒有自己的例項變數,也不能執行類的例項的方法(只有例項物件才可以執行例項方法)。另外例項(-號)方法在類物件中,類物件從父類那裡繼承類方法,就像例項從父類那裡繼承例項方法一樣。
  • 類物件是一個功能完整的物件,所以也能被動態識別(dynamically typed),接收訊息,從其他類繼承方法。特殊之處在於它們是由編譯器建立的,缺少它們自己的資料結構(例項變數),只是在執行時產生例項的代理。

元類物件(metaclass object)

  • 元類物件的實質:類物件是元類物件的一個例項!!元類描述了 一個類物件,就像類物件描述了普通物件一樣。不同的是元類的方法列表是類方法的集合,由類物件的選擇器來響應。當向一個類傳送訊息時,objc_msgSend會通過類物件的isa指標定位到元類,並檢查元類的方法列表(包括父類)來決定呼叫哪個方法。元類代替了類物件描述了類方法,就像類物件代替了例項物件描述了例項化方法。
    很顯然,元類也是物件,也應該是其他類的例項,實際上元類是根元類(root class’s metaclass)的例項,而根元類是其自身的例項,即根元類的isa指標指向自身。
    類的super_class指向其父類,而元類的super_class則指向父類的元類。元類的super class鏈與類的super class鏈平行,所以類方法的繼承與例項方法的繼承也是並行的。而根元類(root class’s metaclass)的super_class指向根類(root class),這樣,整個指標鏈就連結起來了!!

這裡的,類物件是元類物件的一個例項,元類也是物件,也應該是其他類的例項

用官方的圖示簡單的標識就是如下:

5239428-d9e3c09543b3bf59.png
Paste_Image.png

如有錯誤,希望一起探討交流!

相關文章