廢話不多說,要了解OC對象的本質(zhì),先要明確一點,都有哪些是屬于OC的對象:實例對象,類對象,元類對象。
一,Object-C對象
1. instance (實例對象)
即alloc出來的對象,都會有單獨自己的內(nèi)存地址。
實例對象存儲的信息主要有:
- isa指針
- 其他成員變量
2. class(類對象)
每個類在內(nèi)存中有且只有一個class對象。
類對象存儲的信息主要有:
- isa指針
- superclass指針
- 類屬性信息、類的實例對象方法信息(值存儲 -()xxx 這樣的方法)
- 類協(xié)議信息、類成員變量信息(變量的類型和名稱,不存儲具體的賦值)
3. meta-class(元類對象)
每個類在內(nèi)存中有且只有一個meta-class對象。
meta-class對象和class對象的內(nèi)存結(jié)構(gòu)是一樣的,但是用途不一樣,在內(nèi)存中存儲的信息主要包括
- isa指針
- superclass指針
- 類的類方法信息(class method +()xxx)
二,如何分析
大家都知道,OC最后要執(zhí)行,都會轉(zhuǎn)成機器語言(二進制),但是在這個過程中,還做了哪些轉(zhuǎn)換呢?
其實,OC到機器語言,中間還經(jīng)歷了c/c++、匯編語言,最后才到機器語言的。具體看看下面這個圖:

在這里我們主要分析的是:OC到c/c++這一層的轉(zhuǎn)換,看看oc的類、對象所占內(nèi)存、系統(tǒng)分配內(nèi)存、及內(nèi)存信息等
具體怎么操作呢?
1. 按照圖示,將工程目錄cd 到終端

第一個紅框就是程序的main函數(shù),程序的主入口
2. 在終端上輸入
clang -rewrite-objc main.m -o main.cpp
表示重寫main.m文件,最后輸出為main.cpp文件

main.cpp中就是最終轉(zhuǎn)換成C/C++的代碼,只不過這種轉(zhuǎn)換是全平臺的轉(zhuǎn)( win、iphone、Mac),我們并不需要所有的平臺只需要iphone即可
3. 可以在終端敲入下面命令,可以生成只支持ios平臺的c/c++代碼
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main-arm64.cpp
表示在xcode工具下運行 iphone平臺,編譯arm64架構(gòu),重寫 mai.m文件,輸出到 main-arm64.cpp文件
ios上的架構(gòu):模擬器(i386),32bit(armv7),64bit(arm64)

三,OC對象本質(zhì),具體分析
1. 先看看NSObject 轉(zhuǎn)成 C/C++后,長啥樣了
按照下圖所示,找到相應(yīng)代碼,發(fā)現(xiàn),這哥們最后變成了一個結(jié)構(gòu)體
在這個文件里面搜所,大家會發(fā)現(xiàn),好多基于NSObject的結(jié)構(gòu)體,這就說明
【oc的對象、類主要是基于C/C++的結(jié)構(gòu)體實現(xiàn)的】
struct NSObject_IMPL {
Class isa; // 這是一個指針,內(nèi)存大小是8個字節(jié)
};

2. 看一道面試題
面試題:
一個 NSObject 對象占用多少內(nèi)存?
可以理解為,它本身占了多少內(nèi)存,系統(tǒng)給分配了多少內(nèi)存
答案:系統(tǒng)分配了16個字節(jié)給NSObject對象(通過malloc_size函數(shù)獲得),但是NSObject內(nèi)部只使用了8字節(jié)空間(通過class_getInstanceSize函數(shù)獲得)
我們已經(jīng)知道了oc對象、類是基于c/c++的結(jié)構(gòu)體數(shù)據(jù)類型實現(xiàn)的
所以,NSObject本身至少占8字節(jié)的內(nèi)存,但是實際占多少呢,系統(tǒng)又給分配多少呢,看下面的例子
// 導(dǎo)入頭文件
// #import <objc/runtime.h>
// #import <malloc/malloc.h>
NSObject *obj = [[NSObject alloc]init];
// 獲取NSObject類的實例對象的成員變量所占用的大小,就是真正利用的 8 字節(jié)
// Class's ivar size rounded up to a pointer-size boundary.
NSLog(@"%zd", class_getInstanceSize([NSObject class]));
// 獲取obj所指向內(nèi)存的大小,就是系統(tǒng)分配的有 16 字節(jié)
// 搜索 allocWithZone 可以查看
// CF requires all objects be at least 16 bytes.
NSLog(@"%zd", malloc_size((__bridge const void *)(obj)));
從上面的例子中我們可以看出,可以通過兩個函數(shù)來獲取實際占用內(nèi)存和系統(tǒng)分配內(nèi)存的大小
可以在 https://opensource.apple.com/tarballs/objc4/ 查看 objc的源碼, 就知道了 class_getInstanceSize 和 malloc_size 的本質(zhì)
四,總結(jié)
OC對象、類是基于c/c++的設(shè)么數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的
主要是基于結(jié)構(gòu)體實現(xiàn)的,這個可以通過查看源碼驗證
只要大家抓住這個本質(zhì),就會很容易分析出來一個實例對象到底站用多少內(nèi)存,存儲的信息都有哪些
思考:如果創(chuàng)建一個基于NSObject的類,里面有幾個成員變量,再來分析一下內(nèi)存結(jié)構(gòu),看看有什么不同的