Class
就是結構體 objc_class
數組
內部結構以下,須要注意的是objc_class
繼承自objc_object
,那麼裏面就應該有一個isa
。 緩存
參數名 | 類型 | 做用 |
---|---|---|
isa |
Class |
isa指針,指向元類 |
superclass |
Class |
父類 |
chache |
cache_t |
方法緩存,大小由內部成員決定 |
bits |
class_data_bits_t |
存儲了一些數據 |
data |
class_rw_t |
獲取bits 裏存儲的data |
isa
具體請看 isa詳解數據結構
superclass
看變量名就知道這是父類對象,不須要過多解釋app
cache
方法緩存cache
顧名思義是緩存 post
參數名 | 類型 | 大小 | 做用 |
---|---|---|---|
_buckets |
數組 |
8字節 | 存儲一個個結構體bucket_t |
_mask |
mask_t ,實際就是uint32_t |
4字節 | 掩碼 |
_occupied |
mask_t ,實際就是uint32_t |
4字節 | 已緩存的數量 |
接下來看bucket_t
是什麼,bucket_t
有2個成員變量_imp
和key
,這不用多說確定是方法和關鍵值。那麼咱們就能夠猜測,是否是能根據key
獲取到對應的IMP
,進行方法調用?至此也肯定了cache裏緩存的是方法。 ui
bits
和 data
能夠看到bits
是一個64位的數據段,那麼裏面存了什麼數據呢? 3d
在bits
下面緊接了一個data
的聲明,返回的正是bits
裏面的數據。可是類型是class_rw_t
? 指針
class_rw_t
結構methods
方法、properties
屬性、protocols
協議,都是咱們日常在聲明類的時候能看到的,感受至關熟悉。可是裏面還有一個class_ro_t
類型的成員變量ro
引發了個人注意 code
class_ro_t
結構ro
裏也有方法、屬性、協議,還有實例變量,這是爲何呢? cdn
class_rw_t
LGPerson
以下
執行代碼打印獲取到LGPerson
類的結構,能夠直接看到isa
和superClass
。可是怎麼獲取class_rw_t
和class_ro_t
呢?
經過isa
地址向右偏移32位能夠獲取到bits
輸出methods
,看到數量爲4,存儲了咱們聲明的sayHello
方法以及nickName
的setter、getter
方法,可是並無看到sayHappy
方法?
輸出properties
能夠看到咱們聲明的nickName
屬性,符合咱們的預期
輸出protrols
,裏面是空的,也符合預期
至此,對比LGPerson
文件咱們尚未看到sayHappy
方法和成員變量hobby
,猜想它們又被存儲在哪裏呢?來輸出ro
看看
輸出baseMethodList
能夠看到裏面的內容和rw
的methods
是同樣的,沒有sayHappy
方法
輸出baseProperties
,很惋惜依舊沒有找到hobby
輸出ivars
,能夠看到count
爲2,單獨輸出之後咱們能夠看到hobby
和_nickName
都在其中
sayHappy
方法到底去哪裏了?sayHappy
和sayHello
區別在於 sayHello
是實例方法, sayHappy
是類方法。這說明了實例方法存儲在類對象中,類方法不存儲在類對象中。
那麼類方法存在哪裏呢?大膽猜想一下類方法會不會存在元類對象中呢?接下來去元類中尋找一下。
輸出元類的方法列表
bits
和ro
數據重複問題bits
裏面存儲了方法列表、屬性列表等成員變量,爲何還須要ro
再存儲一份?
objc_class
結構中的data()
方法能夠返回bits
的信息,那麼咱們即可以經過setData()
向上查找調用方看看class
賦值流程,也許就能解開這個問題。
找到編譯期間執行的realizeClass
方法,這裏應該就是最初的地方。 但這裏並無對rw
裏面的列表賦值,編譯期間rw
的各個列表應該是空值!
那麼rw的數據又是從哪裏來的呢?這就涉及到了methodizeClass
方法,就是它向rw
中添加類的方法列表、協議列表、屬性列表。
執行了methodizeClass
後ro
中的屬性、對象方法,協議都添加到了rw
中。這樣在class_rw_t
結構中能夠拿到類的相關信息了。也就造成了如下結構:
雖然找到了實現,可是仍是不知道爲何這麼存呀。這就須要看看了realizeClass
在何時調用了。這個時候,prepare_load_methods
引發了個人注意
prepare_load_methods
是加載分類時會調用的方法,結合methodizeClass
咱們會發現分類添加的方法通通都會加入到rw
而不加入ro
。ro
保留着類最原始的數據,後續改變都沒法侵入它!
至此,疑問已經解開,類結構已經解析完畢。
結論以下:
.h
文件聲明屬性會自動生成setter
、getter
、成員變量。ro
中,分類方法存在rw
中