Swift類和對象的底層探索分析
引言
在上文已經(jīng)了解了SIL,接下來主要通過Swift源碼和SIL剖析底層。本文主要通過底層源碼探索類和對象在底層的結(jié)構(gòu)
主要內(nèi)容:
- 對象
- 類
1. 對象
通過源碼中探索Swift對象創(chuàng)建過程以及最終得到的對象結(jié)構(gòu)。
1.1 上層代碼中查找
通過符號斷點調(diào)試來查找底層調(diào)用方法
源碼:
class WYStudent {
var age: Int = 18
var name: String = "WY"
}
var stu = WYStudent();
1.1.1 查找對象調(diào)用方法
通過斷點查看發(fā)現(xiàn)是通過__allocating_init()方法實現(xiàn)對象的創(chuàng)建
添加斷點

查看調(diào)用方法

1.1.2 設(shè)置符號斷點
符號斷點:

查看:

說明:
- 在上面SIL的認(rèn)識中已經(jīng)知道了對象是通過__allocating_init()來創(chuàng)建的,在此處打斷點查看
- 在__allocating_init()方法中可以看到會調(diào)用swift_allocObject()方法
- 因此接下來就需要在源碼中查看該方法
- __allocating_init()方法中做了兩件事
- 調(diào)用swift_allocObject創(chuàng)建對象
- 調(diào)用init()初始化對象,這個init方法是類默認(rèn)提供的,也是默認(rèn)調(diào)用的
1.2 swift_allocObject

說明:
- 通過swift_slowAlloc分配內(nèi)存,并進(jìn)行內(nèi)存字節(jié)對齊,傳入開辟的內(nèi)存空間大小和對齊位數(shù)
- 通過HeapObject方法構(gòu)造一個HeapObject對象,并且綁定到object上
- 因此此時的object就是一個heapObject對象
- 函數(shù)的返回值是HeapObject類型,所以當(dāng)前對象的內(nèi)存結(jié)構(gòu)就是HeapObject的內(nèi)存結(jié)構(gòu)
1.3 swift_showAlloc

// Apple malloc is always 16-byte aligned. # define MALLOC_ALIGN_MASK 15
說明:
- 通過swift_slowAlloc用來分配內(nèi)存空間
- 這里會通過對齊位數(shù)來判斷使用哪種方法來分配空間
- 最小的對齊位數(shù)是16字節(jié),如果傳入的位數(shù)小于16字節(jié),那么就是用16字節(jié)對齊,也就是使用malloc方法
- 如果大于16字節(jié)位數(shù),那么使用AlignedAlloc方法
1.4 查看HeapObject結(jié)構(gòu)體
結(jié)構(gòu)體

refCounts查看:
typedef RefCounts<InlineRefCountBits> InlineRefCounts;
//是一個類,所以它的對象就是8個字節(jié)
class RefCounts {
std::atomic<RefCountBits> refCounts;//引用計數(shù)
...
}
說明:
- 結(jié)構(gòu)體內(nèi)包含一個成員,metadata
- HeapObject()初始化器,會初始化metadata和refCounts,因此對象中會有這兩種屬性
- 其中metadata類型是HeapMetadata,是一個指針類型,占8字節(jié),其實它就是類信息
- refCounts是引用計數(shù),也占有8個字節(jié)
- refCounts的類型是InlineRefCounts
- 而InlineRefCounts是一個類RefCounts的別名
- RefCounts是一個類,所以refCounts占8個字節(jié)
1.5 對象內(nèi)存大小計算

說明:
- metadata占8個字節(jié)
- refCounts占8個字節(jié)
- 再加上age的8個字節(jié)
- name占8個字節(jié)
- 所以總共是40個字節(jié)
1.6 總結(jié)
實例對象的底層結(jié)構(gòu)是HeapObject結(jié)構(gòu)體
默認(rèn)16字節(jié)內(nèi)存大小,metadata 8字節(jié) + refCounts 8字節(jié)
metadata是類信息結(jié)構(gòu),下面會分析
refCounts是引用計數(shù),后面也會詳細(xì)分析
Swift中對象的內(nèi)存分配流程是:
__ allocating_init --> swift_allocObject_ --> _swift_allocObject --> swift_slowAlloc --> malloc
2. 類
對象在底層中的結(jié)構(gòu)是HeapObject結(jié)構(gòu)體,其第一個屬性為metadata,因此從這個屬性出發(fā)來查看類的結(jié)構(gòu)
2.1 查找HeapMetadata
代碼:
using HeapMetadata = TargetHeapMetaData<Inprocess>;
說明:
- 上文可知對象結(jié)構(gòu)體HeapObject包含有HeapMetadata結(jié)構(gòu)體,對象通過它來查找對應(yīng)的類信息
- 點擊進(jìn)入HeapMetadata的定義,發(fā)現(xiàn)它是TargetHeapMetaData類型的別名
- 并且接收了一個參數(shù)Inprocess
2.2. TargetHeapMetaData
代碼:
//模板類型
template <typename Runtime>
struct TargetHeapMetadata : TargetMetadata<Runtime> {
using HeaderType = TargetHeapMetadataHeader<Runtime>;
TargetHeapMetadata() = default;
//初始化方法
constexpr TargetHeapMetadata(MetadataKind kind)
: TargetMetadata<Runtime>(kind) {}
#if SWIFT_OBJC_INTEROP
constexpr TargetHeapMetadata(TargetAnyClassMetadata<Runtime> *isa)
: TargetMetadata<Runtime>(isa) {}
#endif
};
說明:
- TargetHeapMetaData其本質(zhì)是一個模板類型,其中定義了一些所需的數(shù)據(jù)結(jié)構(gòu)
- 這個結(jié)構(gòu)體中沒有屬性,只有初始化方法
- 初始化方法中傳入了一個MetadataKind類型的參數(shù),之后就可以返回TargetMetaData對象
- 同時可以看到這里傳入的kind也就是上面的inprocess了
- 該初始化方法構(gòu)造的對象需要通過該參數(shù)來確定
2.3. TargetMetaData
代碼:

說明:
- 在TargetMetaData中可以看到有一個Kind屬性,這是在構(gòu)建對象時傳入的那個參數(shù)
查看MetadataKind

說明:
- 可以看到它是uint32_t類型
類型

說明:
- 進(jìn)入MetadataKind定義,里面有一個#include "MetadataKind.def"
- 點擊進(jìn)入,其中記錄了所有類型的元數(shù)據(jù)
getClassObject方法:
const TargetClassMetadata<Runtime> *getClassObject() const;
//******** 具體實現(xiàn) ********
template<> inline const ClassMetadata *
Metadata::getClassObject() const {
//匹配kind
switch (getKind()) {
//如果kind是class
case MetadataKind::Class: {
// Native Swift class metadata is also the class object.
//將當(dāng)前指針強(qiáng)轉(zhuǎn)為ClassMetadata類型
return static_cast<const ClassMetadata *>(this);
}
case MetadataKind::ObjCClassWrapper: {
// Objective-C class objects are referenced by their Swift metadata wrapper.
auto wrapper = static_cast<const ObjCClassWrapperMetadata *>(this);
return wrapper->Class;
}
// Other kinds of types don't have class objects.
default:
return nullptr;
}
}
說明:
- 在TargetMetaData結(jié)構(gòu)體定義中有一個方法getClassObject,它就可以用來獲取類對象,也就是類
- 在方法中的核心邏輯是通過kind來判斷當(dāng)前是哪種類型,之后返回
- 這里我們需要的是類類型,因此判斷為MetadataKind::Class,就會返回ClassMetadata類型
驗證:

命令:
po metadata->getKind()
得到其kind是Class
po metadata->getClassObject() + x/8g 0x0000000110efdc70
這個地址中存儲的是元數(shù)據(jù)信息!
說明:
- 傳遞進(jìn)來的Kind發(fā)現(xiàn)可以判斷為類
- 通過方法調(diào)用最后得到的是一個類對象,也就是類
- 通過x/8g查看類信息,里面就是存儲的元數(shù)據(jù)信息
注意:
- TargetMetadata 和 TargetClassMetadata 本質(zhì)上是一樣的
- 因為在內(nèi)存結(jié)構(gòu)中,可以直接進(jìn)行指針的轉(zhuǎn)換,所以可以說,我們認(rèn)為的結(jié)構(gòu)體,其實就是TargetClassMetadata
2.4. TargetClassMetadata
代碼:
template <typename Runtime>
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
...
//swift特有的標(biāo)志
ClassFlags Flags;
//實力對象內(nèi)存大小
uint32_t InstanceSize;
//實例對象內(nèi)存對齊方式
uint16_t InstanceAlignMask;
//運(yùn)行時保留字段
uint16_t Reserved;
//類的內(nèi)存大小
uint32_t ClassSize;
//類的內(nèi)存首地址
uint32_t ClassAddressPoint;
...
}
說明:
- 包含了很多屬性,這些都屬于類結(jié)構(gòu)信息
- 并且它繼承自TargetAnyClassMetadata
2.5. TargetAnyClassMetadata
代碼:

說明:
- TargetAnyClassMetadata是所有的類結(jié)構(gòu),不單單是給Swift用的
- 繼承自TargetHeapMetadata,這也證明類本身也是對象
- 提供有isa、superclass、cache、data,和OC的底層類結(jié)構(gòu)完全一樣
以上就是Swift類和對象的底層探索分析的詳細(xì)內(nèi)容,更多關(guān)于Swift類和對象的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Flutter iOS開發(fā)OC混編Swift動態(tài)庫和靜態(tài)庫問題填坑
這篇文章主要為大家介紹了Flutter iOS OC 混編 Swift動態(tài)庫和靜態(tài)庫問題填坑詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
Swift4.1轉(zhuǎn)場動畫實現(xiàn)側(cè)滑抽屜效果
這篇文章主要為大家詳細(xì)介紹了Swift4.1轉(zhuǎn)場動畫實現(xiàn)側(cè)滑抽屜效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-06-06
Swift 使用 Observe 監(jiān)測頁面滾動的實現(xiàn)方法
這篇文章主要介紹了Swift 使用 Observe 監(jiān)測頁面滾動的實現(xiàn)方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-05-05
理解二叉堆數(shù)據(jù)結(jié)構(gòu)及Swift的堆排序算法實現(xiàn)示例
二插堆即是完全二叉樹,對于排序可以按構(gòu)建最大堆或最小堆的方式來實現(xiàn),這里我們就來共同理解二叉堆數(shù)據(jù)結(jié)構(gòu)及Swift的堆排序算法實現(xiàn)示例2016-07-07
在 Swift 中測試 UIAlertController的方法
這篇文章主要介紹了在 Swift 中測試 UIAlertController的方法的,需要的朋友可以參考下2015-10-10

