ObjC中的類和實例對象

NSObject

OC中類的本質是一個結構體c++

NSObject

NSObject類中存在一個Class類型的isa指針。 咱們在Xcode編寫一個類繼承於NSObject,在terminal使用 xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc xx.m -o xx.cpp 將.m文件轉成.cpp文件,窺探NSObject的底層實現。緩存

NSObject的底層實現

咱們發現NSObject類最後轉成了一個經過typedef struct objc_object NSObject定義的結構體,這大抵就是NSObject的底層實現了。咱們在OC中定義的一個類就是一個C語言的結構體。iphone

有繼承關係的類

定義一個Student繼承自Person類,聲明一個成員變量int No;,依然使用上述命令將其轉成cpp文件,窺探Student的底層實現。函數

Student

Student底層實現

其中student結構體中存在一個Person_IMPL的結構體,這就是Student的父類。因爲我在Person類中聲明瞭一個成員變量age,因此下面是Person_IMPL的結構體的定義。3d

`Person_IMPL`的結構體

而 Person中又存在一個NSObject_IMPL結構體,這是由於Person繼承於NSObject。關於NSObject_IMPL在上面已經介紹過,不作贅述。上述關係能夠經過下圖來表示。指針

繼承關係

ObjC對象的分類

OC中的對象主要能夠分爲實例對象、類對象、元類對象三種。code

  • instance對象(實例對象)

instance對象就是經過類alloc出來的。實例對象中存儲着一個isa指針和一些成員變量cdn

  • class對象 (類對象)

每一個類有且只有一個類對象,class對象中存放着一個isa指針,一個superclass指針,類的屬性信息,類的對象方法信息,類的協議方法信息,類的成員變量信息等,其本質是一個objc_class的結構體。對象

  • meta-class對象 (元類對象)

每一個類有且只有一個元類對象,元類對象的結構跟類對象是同樣只不過用途不同。能夠經過runtime的class_isMetaClass來驗證某個類是否是元類,其本質是一個objc_class的結構體。blog

isa和superclass

isa和superclass

上圖咱們能夠看出:

  • instance的isa指針指向class,class的isa指針指向meta-class,metaclass的isa指針指向root-class
  • subclass的superclass指針指向superclass,依次直到root-class,root-class的superclass指針爲nil。meta-class的superclass指針指向其superclass的meta-class,依次到root-class,root-class的superclass指向rootclass的class。
  • 而subclass和superclass的isa以及meta-class的isa指針皆指向meta-class的root-class。
  • instance調用實例方法的軌跡:經過isa找class,找不到就經過superclass找父類。
  • class調用類對象的軌跡:經過isa找meta-class,找不到就經過superclass找父類。

Class對象分析

在對象分類的類對象和元類對象中已經描述過其中存放的數據,而且說明元類中存放着和類對象同樣結構的數據。

ObjC2之前的類信息

上述是在.cpp文件中找到的類結構體的定義,可是在條件編譯的時候已經明確指出,在ObjC2已經不可用了。因而在runtime源碼中有這樣一個新的定義。

新的ObjC定義

這是一個c++的結構體,他繼承自objc_object,objc_object中有一個isa的成員變量和一些方法。

objc_object

因此objc_class中存在一個isa,superclass指針,以及方法的緩存和類信息數據(bits)。第一個方法class_rw_t *data()中調用了bits的data()函數,返回了一個class_rw_t類型的結構體。

class_rw_t結構體

其中存放有方法列表、屬性列表、協議列表等,其中還有一個class_ro_t的結構體,裏面存放了類的基本信息,包括實例的大小,類名等。

class_ro_t

驗證class

咱們知道了類的本質和結構,那麼咱們能夠本身定義一個結構體,裏面有跟類同樣的變量,將咱們的類轉換成這個結構體,來驗證class的結構。

使用MJ大大編寫的MJClassInfo,定義兩個類,Person(一個成員變量、一個屬性、一個類方法、一個實例方法),Student(一個成員變量、一個類方法、一個實例方法,一個協議),將其轉換成相應的結構體類型,這裏面是mj_objc_class。

窺探class

Person類對象信息

咱們能夠看出定義的實例方法放在method中,屬性放在properties中,成員變量在ro的ivars中...

在student中遵照了一個協議,協議放在類的協議列表中:

student類對象

咱們能夠看到protocols的count爲1,而person沒有遵照協議因此其protocols的count爲0。

使用MJClassInfo中的Meta()方法獲取元類並調用元類結構體的data()方法窺探元類的結構:

meta-class結構

咱們能夠看出metaclass的結構與class 的結構同樣,只不過存儲的數據不同。咱們定義的類方法存儲在metaclass的method中。

兩個問題

  1. 一個NSObject* obj = [[NSObject alloc] init];實例對象佔多少內存空間?

    答:因爲NSObject實例對象就是C語言中的結構體,而這個結構體中僅有一個isa指針,因此其使用的內存空間就是一個指針的內存空間。系統爲NSObject對象分配了16個字節的空間,可是在64位系統中實際使用的只有8個字節,32位系統中實際使用的是4個字節。

2.對象的isa指針指向哪裏?

答:經過isa和superclass的圖例能夠看出實例對象的isa指針指向類對象,類對象的isa指針指向其元類對象,元類對象的isa指針你指向基類。而子類和父類的isa以及元類的isa指針皆指向元類的基類。

相關文章
相關標籤/搜索