案例分析
1帘饶、通過終端cd 到main.m文件所在目錄
2似忧、終端輸入
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m -o main64.cpp
編譯會(huì)得到一個(gè)c++文件(具體問什么這么做呢,可參考iOS底層-對(duì)象的本質(zhì)查看編譯后的文件粘秆,我們可以得出實(shí)例對(duì)象實(shí)質(zhì)為結(jié)構(gòu)體纵穿,該結(jié)構(gòu)體包含類指針和成員變量下隧。
從圖中可以看出
NSObject
也是objc_object
類型的結(jié)構(gòu)體,其內(nèi)部一樣包含isa
指針和其他成員變量谓媒。在內(nèi)存中isa地址就是instance的地址淆院,其他成員變量依次排在后面。打印結(jié)果如下
從打印結(jié)果中可以發(fā)現(xiàn)class1和class2的地址一樣句惯,class3土辩、class4和class5的地址一樣。
通過蘋果官網(wǎng)下載objc源碼抢野,從源碼中我們可以找到
Class
的源碼實(shí)現(xiàn)拷淘。我們可以得出結(jié)論
Class
是objc_class
的結(jié)構(gòu)體指針。那么objc_class
和objc_object
的內(nèi)部是怎么實(shí)現(xiàn)的呢指孤?
struct objc_class : objc_object {
objc_class(const objc_class&) = delete;
objc_class(objc_class&&) = delete;
void operator=(const objc_class&) = delete;
void operator=(objc_class&&) = delete;
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
...代碼太長(zhǎng)省略
struct objc_object {
private:
isa_t isa;
public:
// ISA() assumes this is NOT a tagged pointer object
Class ISA(bool authenticated = false);
// rawISA() assumes this is NOT a tagged pointer object or a non pointer ISA
Class rawISA();
// getIsa() allows this to be a tagged pointer object
Class getIsa();
uintptr_t isaBits() const;
...代碼太長(zhǎng)省略
從源碼從可以看到類中class_rw_t
存儲(chǔ)了變量启涯、方法列表、協(xié)議列表恃轩、版本等信息结洼。
struct class_rw_t {
// Be warned that Symbolication knows the layout of this structure.
uint32_t flags;
uint16_t witness;
#if SUPPORT_INDEXED_ISA
uint16_t index;
#endif
explicit_atomic<uintptr_t> ro_or_rw_ext;
Class firstSubclass;
Class nextSiblingClass;
private:
// 部分代碼已省略
// 方法列表
const method_array_t methods() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->methods;
} else {
return method_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseMethods()};
}
}
// 屬性列表
const property_array_t properties() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->properties;
} else {
return property_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProperties};
}
}
//協(xié)議列表
const protocol_array_t protocols() const {
auto v = get_ro_or_rwe();
if (v.is<class_rw_ext_t *>()) {
return v.get<class_rw_ext_t *>(&ro_or_rw_ext)->protocols;
} else {
return protocol_array_t{v.get<const class_ro_t *>(&ro_or_rw_ext)->baseProtocols};
}
}
};
下面我們通過案例結(jié)合lldb
分析類、元類和根元類
我們可以得到類對(duì)象
isa
指向的類對(duì)象我們稱之為`元類叉跛。實(shí)例方法存儲(chǔ)在類對(duì)象中松忍,類方法存儲(chǔ)在元類對(duì)象中。對(duì)象筷厘、類鸣峭、元類我們一般通過下面的關(guān)系圖說明由圖可見元類的isa
指向基類的元類∷盅蓿基類的元類的 superclass
指向基類
總結(jié)
- 類的本質(zhì)是對(duì)象
- 類對(duì)象是一種數(shù)據(jù)結(jié)構(gòu)摊溶,類存儲(chǔ)的基本信息包含類大小、名稱玖雁、版本更扁、繼承層次和消息與函數(shù)的映射表
- 對(duì)象方法存放在類里面
- 類方法存放在元類里面
- 成員變量存放在
class_ro_t
中的ivar_list_t
- 屬性在
class_rw_t
中的property_array_t
和class_ro_t
中的的property_list_t
都存著一份盖腕,并且會(huì)生成實(shí)例變量赫冬,和對(duì)應(yīng)的方法 - 方法在
class_rw_t
中的method_array_t
和class_ro_t中
的的method_list_t
都存著一份 -
instance
對(duì)象的isa
指向Class
對(duì)象 -
Class
對(duì)象的isa
指向meta-class
對(duì)象 -
meta-class
對(duì)象的isa
指向基類的meta-class
對(duì)象