OC對象的本質(zhì)

做過iOS開發(fā)的同學(xué)都應(yīng)該知道我們平時(shí)編寫的OC代碼的底層實(shí)現(xiàn)都是通過C/C++實(shí)現(xiàn)的,所以O(shè)C的對象都是基于C/C++的數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的

oc代碼的編譯

1、那么OC的對象鹦马、類都是基于C/C++的什么數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的呢?

我們來建立一個(gè)項(xiàng)目將OC的代碼轉(zhuǎn)化到C/C++的代碼來看一下

? ? 1)建立一個(gè)簡單的項(xiàng)目:

項(xiàng)目例子

????2)打開終端進(jìn)入項(xiàng)目文件夾下執(zhí)行命令:$ clang -rewrite-objc main.m -o main.cpp

主意一定要生成cpp文件,如果生成c文件的話會(huì)丟失很多東西的

但是這樣生成的話main.cpp文件會(huì)比較大藐守,所以建議用xcode的一個(gè)指令進(jìn)行指定在什么架構(gòu)下的生成文件:$ xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp

????3)打開main-arm64.cpp文件,搜索NSObject可以查看到

NSObject的底層實(shí)現(xiàn)(IMPL就是實(shí)現(xiàn)的意思)

所以可以看到OC的對象其實(shí)轉(zhuǎn)為C/C++的結(jié)構(gòu)體實(shí)現(xiàn)的蹂风,而結(jié)構(gòu)體中只包含一個(gè)isa的指針變量卢厂,那么根據(jù)C語言的知識(shí)可以看到,isa的指針就是NSObject初始化對象的地址(其實(shí)NSObject的方法和其他的信息都存在其他的地方并不在對象的空間內(nèi)惠啄,后邊會(huì)說)慎恒,那么從目前來看一個(gè)NSObject的對象所占用的空間就是一個(gè)指針?biāo)嫉目臻g(64位下為8個(gè)字節(jié),32位為4個(gè)字節(jié))

D於伞H诩怼!主意:其實(shí)8個(gè)字節(jié)是不嚴(yán)謹(jǐn)?shù)那骶啵筮吔忉專粒氧。。?/p>

2节腐、接下來我們創(chuàng)建兩個(gè)NSObject的子類外盯,Student和Person類摘盆,student繼承person

新建的兩個(gè)類

? ? 2.1那么這兩個(gè)類的存儲(chǔ)空間是多少呢?

? ? 我們知道一個(gè)對象其實(shí)就是一個(gè)C/C++的結(jié)構(gòu)體饱苟,那么我們將這兩個(gè)類和上邊一樣的命令進(jìn)行轉(zhuǎn)化一下發(fā)現(xiàn):

兩個(gè)自定義類對象向C/C++的轉(zhuǎn)換


通過分析person實(shí)例化的對象的內(nèi)存為:4 +8 =12

student實(shí)例化的對象的內(nèi)存為:4 +12 =16

其實(shí)是不對的孩擂,這里會(huì)涉及內(nèi)存對齊的概念,那么我們來看一下這兩個(gè)對象到底占用了多少個(gè)字節(jié)呢箱熬?我們通過代碼來看一下:

通過runtime函數(shù)獲取類的實(shí)例化對象在內(nèi)存中的大小

所以真實(shí)的占用內(nèi)存的大小都是16肋殴,這是因?yàn)閮?nèi)存對齊的原因,對于內(nèi)存對齊大家可以百度查看坦弟。你自己看一下NSObject的實(shí)例對象是多大护锤,其實(shí)是8,所以也證明了對象的內(nèi)存中只存在成員變量的值酿傍,不保存其他的信息烙懦。

????2.2我們還可以對對象的占用內(nèi)存細(xì)節(jié)借助xcode看一下:

? ? 1)打上斷點(diǎn)然后View->Memory如圖:


? ? 2)

? ? ? ? 由此也能看出stu的實(shí)力化對象一共所占用16個(gè)字節(jié),_age =06 00 00 00? ? ?_no =09 00 00 00

? ? ? ? 所以再次證明:一個(gè)類的實(shí)例化對象的內(nèi)存只保存屬性值赤炒,不會(huì)包含其他信息

3氯析、由上邊的一系列操作可以看出一個(gè)類的實(shí)例化對象的內(nèi)存只保存屬性值,不會(huì)包含其他信息莺褒,但是其他的類的信息都保存在哪兒呢掩缓?而且上邊還有一個(gè)細(xì)節(jié)那就是實(shí)例化對象的isa的值(指針)到底指向哪兒?

先說結(jié)論:Objective-C中的對象遵岩,簡稱OC對象你辣,主要可以分為3種

? ? ? ? ? ? ?1)instance對象(實(shí)例對象)就是通過類alloc出來的對象,每次調(diào)用alloc都會(huì)產(chǎn)生新的instance對象尘执,instance對象在內(nèi)存中存儲(chǔ)的信息包括舍哄、isa指針、其他成員變量

? ? ? ? ? ? ?2)class對象(類對象)每個(gè)類在內(nèi)存中有且只有一個(gè)class對象誊锭,class對象在內(nèi)存中存儲(chǔ)的信息主要包含:isa指針表悬、superclass指針、類的屬性信息(@property)丧靡、類的對象方法信息(instance method)蟆沫、類的協(xié)議信息(protocol)、類的成員變量信息(ivar)温治、......

? ? ? ? ? ? ?3)meta-class對象(元類對象)meta-class對象和class對象的內(nèi)存結(jié)構(gòu)是一樣的饭庞,但是用途不一樣。meta-class對象在內(nèi)存中存儲(chǔ)的信息主要包含:isa指針罐盔、superclass指針但绕、類的類方法信息(class method)、......

? ? 3.1我們先證明兩個(gè)個(gè)細(xì)節(jié):1)每個(gè)類的內(nèi)存中有且只有一個(gè)class對象

證明class對象在內(nèi)存中有且只有一個(gè)

? ? ? ? ? ? ? ? 2)meta_class對象在內(nèi)存中也是一個(gè)但和class對象不是一個(gè)內(nèi)存哦,他們都是class 類型捏顺,所以他們的結(jié)構(gòu)都是一樣的六孵。內(nèi)存是一個(gè)可以分析出來,因?yàn)閏lass的對象都是一個(gè)幅骄,而獲取元類的對象都是從class對象獲取的劫窒,所以肯定是一樣的。

獲取meta_class的方法:

????????Class metaClass =object_getClass([NSObject class]);//獲取類對象的類就是元類拆座,但是不能[[NSObject class]class]這樣獲取主巍,這樣獲取永遠(yuǎn)只是類對象!只能通過runtime的方法獲扰泊铡孕索!

查看Class是否為meta-class:


檢查某個(gè)class對象是否為元類

? ? 3.2再來看一下各個(gè)對象的isa指針到底指向誰呢?

借用網(wǎng)上一張圖:

oc對象的isa和superclass指針指向

由圖看出來instance對象的isa指向class躏碳,class對象的isa指向meta_class搞旭。由此可見:oc的對象的方法調(diào)用就可以串起來了,例如之前的student的instance對象調(diào)用對象方法:

Student *stu =[[Student? alloc]init];

[stu? studentMethod];

stu的指針就是isa的指針菇绵,而isa指向student的class肄渗,那么其實(shí)就是student的class對象調(diào)用的studentMethod,所以就可以分析出一個(gè)類的對象方法信息其實(shí)放在class中的咬最,分析一下:因?yàn)樗械膶?shí)例化對象的方法都一樣翎嫡,沒必要在每個(gè)對象中都開辟一份內(nèi)存空間來放方法信息,因?yàn)檫@是對內(nèi)存利用不科學(xué)的永乌,所以放在class對象中是比較好的

接下來我們證明一下

? ? 1)新建項(xiàng)目:(這里面的lldb指令我就不再解釋了)

stu的isa的指針和stu的class的地址

很明顯stu的isa的指針和stu的class對象的地址是不一樣的惑申,跟我們上邊說的結(jié)論不一樣,那是因?yàn)閺膇sa指針到class的地址是要做一次位運(yùn)算的铆遭,根據(jù)架構(gòu)不同&的值一不一樣:


如果想直接看到ISA_MASK的值的話硝桩,可以到apple官網(wǎng)下載runtime的源碼查找,這里就不在尋找了枚荣,直接驗(yàn)證:

通過一次位運(yùn)算之后很明顯的結(jié)果是一樣的,說明之前的結(jié)論是對的啼肩,我這兒是模擬器所以使用的是第二個(gè)ISA_MASK值橄妆,你如果使用真機(jī)測試的話那么請使用第一個(gè)ISA_MASK值進(jìn)行運(yùn)算。

接下來的Person和NSObject的驗(yàn)證可以自己進(jìn)行祈坠。還有那幅圖的superclass的指向都可以通過LLDB指令進(jìn)行驗(yàn)證:接下來我們驗(yàn)證一下superclass的那條線的指向:


很明顯指向跟上邊的那個(gè)圖是一樣的

然后我們在去看一下calss對象里面都有什么害碾,其實(shí)可以從之前從apple官網(wǎng)下載的代碼可以找到的,這個(gè)不方便演示但是我們可以借助xcode來證明一下:我們來借助mj老師的文件MJClassInfo.h里面的mj_objc_class的結(jié)構(gòu)體來將class的對象強(qiáng)轉(zhuǎn)到結(jié)構(gòu)體來窺探下class里面的東西:(這里面會(huì)涉及一點(diǎn)c++的知識(shí)赦拘,你只要知道上邊的結(jié)論也就行了慌随,證明作為了解):

Class和MetaClass對象強(qiáng)轉(zhuǎn)換為結(jié)構(gòu)體


personClassData的內(nèi)部信息


studenClassData的信息

其他的信息自己可以看下就可以看出class和metaClass對象里面的信息了如圖:

各個(gè)對象所儲(chǔ)存的信息

(主意,在打印的屬性列表里面只顯示第一個(gè)屬性,其他的屬性需要操作指針位移運(yùn)算來訪問其他的屬性阁猜,作為了解丸逸。還有元類對象雖然有屬性列表,但是里面都是空的剃袍,因?yàn)樗旁陬悓ο罄锩娴幕聘铡_€有在上邊打印的里面method_list是個(gè)數(shù)組,調(diào)用的時(shí)候也是一個(gè)個(gè)往下尋找民效,但是如果經(jīng)常被調(diào)用的時(shí)候那么這個(gè)方法會(huì)放入一個(gè)cache里面用于快速調(diào)用)

至此我們已經(jīng)看到oc對象的本質(zhì)了憔维,但是我們前邊有個(gè)不嚴(yán)謹(jǐn)?shù)恼f法是:一個(gè)NSObject對象占用8個(gè)字節(jié),32bit下占用4個(gè)字節(jié)畏邢。其實(shí)底層做了改變业扒,其實(shí)是開辟了16個(gè)字節(jié),但是實(shí)際使用的的確是8或者4個(gè)字節(jié)舒萎。怎么看一下呢程储?在源碼里面可以看到這個(gè)函數(shù):


所以其實(shí)是一個(gè)對象至少分配16個(gè)字節(jié)!但是實(shí)際使用為8個(gè)字節(jié)逆甜,也可以用runtime的一函數(shù)


實(shí)際占用的空間和開辟的空間


最后的最后留個(gè)問題:給NSObject增加一個(gè)對象方法虱肄,那么[Student test]和[NSObject test],通過類調(diào)用test方法會(huì)報(bào)錯(cuò)么?交煞?咏窿?(主意分析上邊網(wǎng)上的那張圖和一個(gè)方法的調(diào)用順序分析一下就知道了)

ps:這個(gè)文章其實(shí)是我的學(xué)習(xí)筆記了,在小碼哥學(xué)習(xí)李明杰老師的網(wǎng)絡(luò)授課做得筆記素征,所以用了好多mj老師的東西集嵌,再次聲明一下,感謝mj老師在it界耕耘御毅!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末根欧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子端蛆,更是在濱河造成了極大的恐慌凤粗,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件今豆,死亡現(xiàn)場離奇詭異嫌拣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)呆躲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門异逐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人插掂,你說我怎么就攤上這事灰瞻⌒壤” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵酝润,是天一觀的道長燎竖。 經(jīng)常有香客問我,道長袍祖,這世上最難降的妖魔是什么底瓣? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蕉陋,結(jié)果婚禮上捐凭,老公的妹妹穿的比我還像新娘。我一直安慰自己凳鬓,他們只是感情好茁肠,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缩举,像睡著了一般垦梆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仅孩,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天托猩,我揣著相機(jī)與錄音,去河邊找鬼辽慕。 笑死京腥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的溅蛉。 我是一名探鬼主播公浪,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼船侧!你這毒婦竟也來了欠气?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤镜撩,失蹤者是張志新(化名)和其女友劉穎预柒,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體袁梗,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡卫旱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了围段。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡投放,死狀恐怖奈泪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤涝桅,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布拜姿,位于F島的核電站,受9級特大地震影響冯遂,放射性物質(zhì)發(fā)生泄漏蕊肥。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一蛤肌、第九天 我趴在偏房一處隱蔽的房頂上張望壁却。 院中可真熱鬧,春花似錦裸准、人聲如沸展东。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽盐肃。三九已至,卻和暖如春权悟,著一層夾襖步出監(jiān)牢的瞬間砸王,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工峦阁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谦铃,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓拇派,卻偏偏與公主長得像荷辕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子件豌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉疮方,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,679評論 0 9
  • iOS底層原理總結(jié) - 探尋OC對象的本質(zhì) 對小碼哥底層班視頻學(xué)習(xí)的總結(jié)與記錄。面試題部分茧彤,通過對面試題的分析探索...
    xx_cc閱讀 21,199評論 31 177
  • Objective-C語言是一門動(dòng)態(tài)語言骡显,它將很多靜態(tài)語言在編譯和鏈接時(shí)期做的事放到了運(yùn)行時(shí)來處理。這種動(dòng)態(tài)語言的...
    有一種再見叫青春閱讀 577評論 0 3
  • 本文基于objc4-709源碼進(jìn)行分析曾掂。關(guān)于源碼編譯:objc - 編譯Runtime源碼objc4-706 ob...
    WeiHing閱讀 809評論 1 3
  • 1 感謝前天 “逝者不可追惫谤,來者猶可待≈橄矗”前天已經(jīng)過去溜歪,前天種種我們無力改變,但是我們必須心存感激:感謝父母給我們...
    Constance1993閱讀 239評論 0 0