iOS isa詳解

1、isa 在哪裏

有以下代碼,在控制檯輸出obj的數據結構,排在第一位的就是isa的地址。 數據結構

爲何呢?由於對象繼承自NSObjectNSObject在底層的實現是結構體objc_object,裏面只有一個isa成員變量,那麼對象的首地址指向的第一塊就是isa所在。架構

2、isa 的類型

正常來講isa指向的就是該對象的類,那咱們打印這個地址應該輸出類名,可是出乎意料的是這裏並無打印出類名。 ide

去源碼裏面找找看,發現isaClass類型函數

Class類型實際上是objc_class post

能夠看到objc_class繼承自objc_object,那麼裏面就應該有一個isa。此外還有的成員變量就是superclasscachebitsdata優化

3、isa 的結構

可是不行,這樣也看不出來什麼呀,仍是不知道isa究竟是什麼。有看過 iOS alloc & init 方法解析 的朋友應該有印象,在alloc方法裏面會調用一個叫initIsa()的方法,那麼是否是能夠在這個方法中找到isa的真正結構呢?3d

終於找到了,原來isa_t是個聯合體,看下來重點就應該在ISA_BITFIELD指針

喜大普奔終於找到了,注意的咱們要關注arm64下的結構。前面的是參數名、後面的是所佔位數,總數加起來是64位。 調試

參數名 做用 大小 所在位置
nonpointer 是否對isa指針開啓指針優化
0:純isa指針只包含類對象地址
1:isa中包含了類對象地址、類信息、對象的引用計數等
1 0
has_assoc 是否有關聯對象
0:沒有
1:存在
1 1
has_cxx_dtor 該對象是否有C++或者Objc的析構器
若是有析構函數則須要作析構邏輯
若是沒有則能夠更快的釋放對象
1 2
shiftcls 存儲類指針的值。開啓指針優化的狀況下,在arm64架構中有 33 位用來存儲類指針 33 3~35
magic 用於調試器判斷當前對象是真的對象仍是沒有初始化的空間 5 36~40
weakly_referenced 是否有弱引用
0:沒有
1:存在
1 41
deallocating 是否正在釋放內存
0:不是
1:是
1 42
has_sidetable_rc 是否須要用到外掛引用計數,當對象引用技術大於 10 則須要借用該變量存儲進位 1 43
extra_rc 該對象的引用計數值,其實是引用計數值減 1。 若是對象的引用計數爲10,那麼 extra_rc 爲 9。若是引用計數大於 10 則須要使用 has_sidetable_rc 19 44~63

那麼咱們知道了,在開啓isa優化的時候對象的指針是存在isashiftcls裏面,那麼怎麼得到shiftcls呢?咱們強轉isa的類型爲isa_t後打印code

4、isa 獲取類

shiftcls是有了,可是這裏面還不是類?這時候咱們再來看shiftcls是怎麼來的。

原來是cls右移3位。那麼咱們把它還原一下,成功~

5、怎麼從對象獲取類

日常獲取對象的類會直接調用class方法,那麼class方法內部實現是怎樣的?

重點來了,getIsa()方法;

當前不是taggedPointer,直接返回ISA()

ISA()裏面根據判斷條件就會走到最後的一行,就是isa.bitsISA_MASK作一下與運算

咱們來看看ISA_MASK

ISA_MASK有了,可是isa.bits怎麼獲取呢??這裏打印isa出來的數值和結構裏bits的值如出一轍!

那麼咱們嘗試一下~把isa打印的值和ISA_MASK與運算~成功獲取到類

6、ISA的指向

這個時候已經驗證了能夠經過對象的isa獲取到對象的類,那麼類自己也是一個對象,它的isa又是指向那裏呢?

  • 簡單的多打印幾層,咱們看到打印結果有3層是LGPerson,第一層是咱們的對象,第二層是類對象。第三層雖然也是LGPerson,可是地址和第二層的不同,說明不是同一個對象。類對象在內存中是隻能存在一個的,那麼第三層確定就是元類了。
  • 往上繼續打印,發現元類對象isa指向的是NSObjectNSObject的象isa指向的也是NSObject。看看2個NSObject的地址是相同的,因此NSObjectisa是指向了自身,也就是NSObjectLGPerson具備同一個根元類。

那麼咱們能夠獲得四個結論

  • 對象的isa指向其類
  • 類對象的isa指向其元類
  • 元類的isa指向根元類
  • 全部元類的isa都指向根元類

相關文章
相關標籤/搜索