isa結(jié)構(gòu)分析

在開始分析isa前盆赤,我們得先搞清楚一個問題:對象是什么熔恢?即對象的本質(zhì)是什么筑累?要搞清這個問題我們還得先了解一下Clang犁珠。

一、Clang

1.Clang是什么

Clang是?個由Apple主導(dǎo)編寫互亮,基于LLVMC/C++/Objective-C編譯器犁享。

2.Clang的使用

Clang的使用語法有很多,這里就不一一舉例了豹休,有興趣的可以自行搜索炊昆,今天我們用到的語法如下:

//將目標(biāo)文件編譯成c++文件
clang -rewrite-objc main.m -o main.cpp

同時Xcode在安裝的時候順帶安裝了xcrun命令,xcrun命令在clang的基礎(chǔ)上進(jìn)?了?些封裝威根,要更好??些凤巨,用法如下:

//模擬器
xcrun -sdk iphonesimulator clang -arch arm64 -rewrite-objc main.m -o 
main-arm64.cpp
//手機(jī)
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main?arm64.cpp

簡單了解完Clang,我們來使用看看吧洛搀。

二敢茁、對象的本質(zhì)

1.使用上述clang語法,我們得到了一個cpp文件留美,如下圖:

編譯后得到的cpp文件
2.打開并搜索LGPerson卷要,看一下編譯前后有什么不同,如下圖:

編譯前后對比圖
3.我們可以看到独榴,編譯后LGPerson變成了一個結(jié)構(gòu)體(struct)僧叉,并且定義的屬性name變成了結(jié)構(gòu)體數(shù)據(jù)成員,同時還多了一個struct NSObject_IMPL NSObject_IVARS棺榔,并且也是一個結(jié)構(gòu)體瓶堕。

4.LGPerson繼承自NSObject,它在編譯后必然也是一個結(jié)構(gòu)體症歇,如下圖:

編譯后的NSObject
可以看到郎笆,這里是將NSObject結(jié)構(gòu)體作為LGPerson第一個數(shù)據(jù)成員,并且NSObject中有一個isa數(shù)據(jù)成員忘晤,這個屬于偽繼承宛蚓,意味著LGPerson擁有NSObject中的所有成員,所以NSObject_IVARS就等效于isa设塔。

總結(jié)對象的本質(zhì)其實就是結(jié)構(gòu)體凄吏,LGPerson中的isa繼承自NSObjectisa

三闰蛔、isa分析

alloc探索中痕钢,核心三步中有一個initInstanceIsa方法,進(jìn)入源碼序六,發(fā)現(xiàn)調(diào)用的是initIsa方法任连,如下圖:

isa的初始化
可以看到,isa是通過isa_t類型初始化的例诀,那isa_t又是什么類型的呢随抠?帶著疑問裁着,我們進(jìn)一步探索,發(fā)現(xiàn)isa_t是一個聯(lián)合體(union)拱她,那聯(lián)合體又是什么呢跨算?

1.聯(lián)合體(union)

聯(lián)合體(union)也叫共用體結(jié)構(gòu)體(struct)一樣都是構(gòu)造數(shù)據(jù)類型。

結(jié)構(gòu)體

所有變量都是共存的椭懊,它們占用不用的內(nèi)存诸蚕,優(yōu)點:容量大成員間互不影響氧猬;缺點:不管用不用背犯,都會為成員分配內(nèi)存,浪費內(nèi)存盅抚。

聯(lián)合體

所有變量都是互斥的漠魏,它們共用一段內(nèi)存,優(yōu)點:節(jié)省內(nèi)存空間妄均;缺點:包容性弱柱锹,共用體使用了內(nèi)存覆蓋技術(shù)同一時刻只能保存一個成員的值丰包,即如果對新的成員賦值禁熏,就會把原來成員的值覆蓋掉

2.isa_t

isa_t的結(jié)構(gòu)如下圖:

isa_t的結(jié)構(gòu)
可以看到邑彪,聯(lián)合體中定義了兩個成員clsbits和一個結(jié)構(gòu)體位域ISA_BITFIELD(用來存放類信息其他信息)瞧毙。

clsbits說明這里有兩種初始化方式:
1.通過cls初始化:即isa的初始化圖中的isa = isa_t((uintptr_t)cls)
2.通過bits初始化:即else部分

3.位域

有些數(shù)據(jù)在存儲時并不需要占用一個完整的字節(jié),只需要占用一個或幾個二進(jìn)制位即可寄症≈姹耄基于這種的數(shù)據(jù)結(jié)構(gòu),就是位域有巧。

這里ISA_BITFIELD就是一個位域释漆,它有兩個版本,分別對應(yīng)__arm64____x86_64__篮迎,即iOSmacOS男图,如下圖:

位域ISA_BITFIELD
1.nonpointer:表示是否對 isa 指針開啟指針優(yōu)化
0:純isa指針
1:不?是類對象地址,isa 中包含了類信息柑潦、對象的引?計數(shù)

2.has_assoc:是否關(guān)聯(lián)對象標(biāo)志位
0:沒有
1:存在

3.has_cxx_dtor:該對象是否有 C++ 或者 Objc 的析構(gòu)器
如果析構(gòu)函數(shù)(類似于OC中的dealloc),則需要做析構(gòu)邏輯,
如果沒有,則可以更快的釋放對象

4.shiftcls: 存儲類指針的值
arm64:開啟指針優(yōu)化的情況下享言,在 arm64 架構(gòu)中有33位?來存儲類指針
x86_64:有44位用來存儲類指針

5.magic:?于調(diào)試器判斷當(dāng)前對象是真的對象還是沒有初始化的空間

6.weakly_referenced:對象是否被指向或者曾經(jīng)指向?個ARC的弱變量
沒有弱引?的對象可以更快釋放

7.deallocating:標(biāo)志對象是否正在釋放內(nèi)存

8.has_sidetable_rc:當(dāng)對象引?技術(shù)?于10時,則需要借?該變量存儲進(jìn)位

9.extra_rc:當(dāng)表示該對象的引?計數(shù)值渗鬼,實際上是引?計數(shù)值減 1
如果對象的引?計數(shù)為 10,那么 extra_rc為 9
如果引?計數(shù)?于 10荧琼,則需要使?到has_sidetable_rc

isa的存儲分布如下圖:

isa存儲分布圖

4.分析

我們跟隨代碼來到initIsa方法中譬胎,如下圖:

isa的初始化
1.根據(jù)nonpointer參數(shù)為true差牛,這里執(zhí)行了else的操作,創(chuàng)建了newisa聯(lián)合體堰乔,打印結(jié)果如下圖:

賦值前的newisa
2.使用ISA_MAGIC_VALUEbits進(jìn)行賦值偏化,看一下賦值后的結(jié)果,如下圖:

賦值后的newisa
通過對比镐侯,發(fā)現(xiàn)這里給cls賦值0x001d800000000001侦讨,因為在給bits賦值時,會為cls追加默認(rèn)值苟翻,但是為什么magic賦值了59呢?

打開計算器并輸入0x001d800000000001韵卤,從47位開始讀取6位,將59轉(zhuǎn)二進(jìn)制崇猫,發(fā)現(xiàn)都為111011沈条,如下圖:

59的由來
可以看出,這里進(jìn)行了進(jìn)制轉(zhuǎn)換诅炉,將指針地址二進(jìn)制蜡歹,并從47位開始讀取6位,再轉(zhuǎn)換成十進(jìn)制涕烧。但是為什么是從47開始呢月而?

根據(jù)賦值后的newisa圖,前面有4個位域nonpointer占1位议纯,has_assoc占1位景鼠,has_cxx_dtor占1位,shiftcls占44位)共占了47位痹扇,所以magic47位開始铛漓。

3.通過newisa.shiftcls = (uintptr_t)cls >> 3關(guān)聯(lián)類信息。

isa關(guān)聯(lián)到類
可以看到鲫构,這里shiftcls已經(jīng)賦上了右移后得到的值536871986浓恶,同時cls也從默認(rèn)值變成了LGPerson,實現(xiàn)了isa與類的關(guān)聯(lián)结笨。

這里需要注意兩點:
為什么shiftcls需要強轉(zhuǎn)類型包晰?
因為此時,cls可能是個字符串炕吸,直接存儲會導(dǎo)致無法識別伐憾,所以強轉(zhuǎn)成uintptr_tunsigned long類型)

為什么需要右移3位
因為shiftcls前面還有3個位域,為了避免影響它們赫模,故右移將它們抹零树肃。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市瀑罗,隨后出現(xiàn)的幾起案子胸嘴,更是在濱河造成了極大的恐慌雏掠,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劣像,死亡現(xiàn)場離奇詭異乡话,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)耳奕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門绑青,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人屋群,你說我怎么就攤上這事闸婴。” “怎么了谓晌?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵掠拳,是天一觀的道長。 經(jīng)常有香客問我纸肉,道長溺欧,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任柏肪,我火速辦了婚禮姐刁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘烦味。我一直安慰自己聂使,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布谬俄。 她就那樣靜靜地躺著柏靶,像睡著了一般。 火紅的嫁衣襯著肌膚如雪溃论。 梳的紋絲不亂的頭發(fā)上屎蜓,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機(jī)與錄音钥勋,去河邊找鬼炬转。 笑死,一個胖子當(dāng)著我的面吹牛算灸,可吹牛的內(nèi)容都是我干的扼劈。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼菲驴,長吁一口氣:“原來是場噩夢啊……” “哼荐吵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤捍靠,失蹤者是張志新(化名)和其女友劉穎沐旨,沒想到半個月后森逮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體榨婆,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年褒侧,在試婚紗的時候發(fā)現(xiàn)自己被綠了良风。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡闷供,死狀恐怖烟央,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情歪脏,我是刑警寧澤疑俭,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站婿失,受9級特大地震影響钞艇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜豪硅,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一哩照、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧懒浮,春花似錦飘弧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至稽穆,卻和暖如春冠王,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背秧骑。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工版确, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人乎折。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓绒疗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親骂澄。 傳聞我的和親對象是個殘疾皇子吓蘑,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344