在上一篇文章中, 我著重介紹了 Swift中指針的使用, 這篇文章主要圍繞以下幾點(diǎn):
- HandyJSON 的優(yōu)勢(shì).
- HandyJSON 解析數(shù)據(jù)的原理.
- Mirror 的原理.
HandyJSON 的優(yōu)勢(shì)
JSON(JavaScript Object Notation) 是一種輕量級(jí)的數(shù)據(jù)交換格式, 應(yīng)用廣泛. 在 App 的使用過(guò)程中, 服務(wù)端給移動(dòng)端發(fā)送的大部分都是 JSON 數(shù)據(jù), 移動(dòng)端需要解析數(shù)據(jù)才能做進(jìn)一步的處理. 在解析JSON數(shù)據(jù)這一塊, 目前 Swift 中流行的框架基本上是 SwiftyJSON, ObjectMapper, JSONNeverDie, HandyJSON 這么幾種.
我們應(yīng)該如何選擇呢?
首先我們應(yīng)該先明白解析 JSON 的原理. 目前有兩個(gè)方向.
保持 JSON 語(yǔ)義, 直接解析 JSON.
SwiftyJSON 就是這樣的. 本質(zhì)上仍然需要根據(jù) JSON 結(jié)構(gòu)去取值.預(yù)定義 Model 類(lèi), 將 JSON 反序列化類(lèi)的實(shí)例, 再使用這些實(shí)例.
這種方式和 OC 中的 MJExtension 的思路是一致的. 在 Swift 中,ObjectMapper
,JSONNeverDie
, 以及HandyJSON
做的都是將 JSON 文本反序列化到 Model 類(lèi)上.
第二種思路是我們熟悉和比較方便的. 和服務(wù)端定義好數(shù)據(jù)結(jié)構(gòu), 寫(xiě)好 Model 就可以直接解析.
第二種思路有三種實(shí)現(xiàn)方式:
- 完全沿用 OC 中的方式, 讓 Model 類(lèi)繼承自
NSObject
, 通過(guò)class_copyPropertyList
方法拿到 Model 的各種屬性, 從 JSON 中拿到對(duì)應(yīng)的 value, 再通過(guò) OC 中 利用runtime
機(jī)制 實(shí)現(xiàn)的KVC
方法為屬性賦值. 如JSONNeverDie
. - 支持純
Swift
類(lèi), 但要求開(kāi)發(fā)者實(shí)現(xiàn)mapping
函數(shù), 使用重載的運(yùn)算符進(jìn)行賦值, 如ObjectMapper
. - 獲取到 JSON 數(shù)據(jù)后, 直接在內(nèi)存中為實(shí)例的屬性賦值.
HandyJSON
就是這樣實(shí)現(xiàn)的.
- 第一種方式的缺點(diǎn)在于需要強(qiáng)制繼承
NSObject
, 這不適用于struct
定義的 Model. 因?yàn)?struct
創(chuàng)建的 Model 不能通過(guò) KVC 為其賦值. - 第二種方式的缺點(diǎn)在于自定義
mapping
函數(shù), 維護(hù)比較困難. - 第三種方式在使用上和
MJExtension
基本差不多, 比較方便. 是我們所推薦的.
HandyJSON 解析數(shù)據(jù)的原理.
如何在內(nèi)存上為實(shí)例的屬性賦值呢?
在上一篇文章里, 我們介紹了 struct 實(shí)例 和 class 實(shí)例在內(nèi)存上結(jié)構(gòu)的不同. 為屬性賦值, 我們需要以下步驟:
- 獲取到屬性的名稱(chēng)和類(lèi)型.
- 找到實(shí)例在內(nèi)存中的 headPointer, 通過(guò)屬性的類(lèi)型計(jì)算內(nèi)存中的偏移值, 確定屬性在內(nèi)存中的位置.
- 在內(nèi)存中為屬性賦值.
在 Swift 中實(shí)現(xiàn)反射機(jī)制的類(lèi)是 Mirror
, 通過(guò) Mirror
類(lèi)可以獲取到類(lèi)的屬性, 但是不能為屬性賦值, 它是可讀的. 但是我們可以直接在內(nèi)存中為實(shí)例賦值. 這是一種思路. 另外一種思路是不利用 Mirror
, 直接在內(nèi)存中獲取到屬性的名稱(chēng)和類(lèi)型, 這也是可以的. 目前 HandyJSON
就是利用的第二種方式.
Mirror 的原理
雖然 HandyJSON 的核心實(shí)現(xiàn)上并沒(méi)有依賴(lài)于 Mirror
, Mirror 的性能不好. 但是這個(gè)類(lèi)還是挺有意思的. 如果沒(méi)使用過(guò) Mirror, 看看這篇文章.
class LCPerson {
var name: String?
}
Mirror(reflecting: LCPerson()).children.forEach { (child) in
print(child.label ?? "", child.value)
child.value = "lili" // error胚想,不能直接賦值
}
下面的內(nèi)容極大的借鑒了一個(gè)牛人寫(xiě)的 how-mirror-works, 所以也算是我的學(xué)習(xí)筆記.
要從源碼角度剖析 Mirror, 我們需要拿到 Swift 的源碼, 可以從 Apple 的 官方 github clone 源代碼到本地. 我們需要真正關(guān)注的是 stdlib
和 include
這兩個(gè)文件夾, 前者是 Swift 的標(biāo)準(zhǔn)庫(kù)的源碼, 后者是支持文件.
反射的 API 有一部分是用 Swift 實(shí)現(xiàn)的, 另一部分是 C++ 實(shí)現(xiàn)的. 分別在 ReflectionMirror.swift 和 ReflectionMirror.mm. 這兩者通過(guò)一小組暴露給 Swift 的 C++ 函數(shù)進(jìn)行通信.
比如在 ReflectionMirror.swift
中的.
@_silgen_name("swift_reflectionMirror_subscript")
internal func _getChild<T>(
of: T,
type: Any.Type,
index: Int,
outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any
與其在 ReflectionMirror.mm
中的實(shí)現(xiàn)是下面
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
AnyReturn swift_reflectionMirror_subscript(OpaqueValue *value, const Metadata *type,
intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *),
const Metadata *T) {
return call(value, T, type, [&](ReflectionMirrorImpl *impl) {
return impl->subscript(index, outName, outFreeFunc);
});
}
注意:
-
ReflectionMirror.swift
中的_getChild()
函數(shù)用于獲取對(duì)應(yīng)索引值的子元素信息. -
@_silgen_name
修飾符會(huì)通知 Swift 編譯器將這個(gè)函數(shù)映射成swift_reflectionMirror_subscript
符號(hào)疗韵,而不是 Swift 通常對(duì)應(yīng)到的_getChild
方法名修飾. 也就是說(shuō), 在 Swift 中直接調(diào)用_getChild
函數(shù), 實(shí)際上就是調(diào)用 C++ 實(shí)現(xiàn)的swift_reflectionMirror_subscript
函數(shù). -
SWIFT_CC(swift)
會(huì)告訴編譯器這個(gè)函數(shù)使用的是 Swift 的調(diào)用約定疮装,而不是 C/C++ 的.SWIFT_RUNTIME_STDLIB_INTERFACE
標(biāo)記這是個(gè)函數(shù). - C++ 的參數(shù)會(huì)去特意匹配在 Swift 中聲明的函數(shù)調(diào)用. 當(dāng) Swift 調(diào)用
_getChild
時(shí), C++ 會(huì)用包含的 Swift 值指針的value
, 包含類(lèi)型參數(shù)的type
, 包含目標(biāo)索引值的index
, 包含標(biāo)簽信息的outname
, 包含釋放目標(biāo)字符串內(nèi)存的方法outFreeFunc
, 包含類(lèi)型相應(yīng)的范型 <T> 的T
的函數(shù)參數(shù)來(lái)調(diào)用此函數(shù).
Mirror 的在 Swift 和 C++ 之間的全部接口由以下函數(shù)組成:
獲取標(biāo)準(zhǔn)化類(lèi)型
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
獲取子元素?cái)?shù)量
@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount<T>(_: T, type: Any.Type) -> Int
獲取子元素信息
@_silgen_name("swift_reflectionMirror_subscript")
internal func _getChild<T>(
of: T,
type: Any.Type,
index: Int,
outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any
// Returns 'c' (class), 'e' (enum), 's' (struct), 't' (tuple), or '\0' (none)
獲取對(duì)象的展示類(lèi)型
@_silgen_name("swift_reflectionMirror_displayStyle")
internal func _getDisplayStyle<T>(_: T) -> CChar
@_silgen_name("swift_reflectionMirror_quickLookObject")
internal func _getQuickLookObject<T>(_: T) -> AnyObject?
判斷一個(gè)類(lèi)是不是另一個(gè)類(lèi)的子類(lèi), 類(lèi)似于 NSObject 中的 isKindOfClass
@_silgen_name("_swift_stdlib_NSObject_isKindOfClass")
internal func _isImpl(_ object: AnyObject, kindOf: AnyObject) -> Bool
動(dòng)態(tài)派發(fā)
元組、結(jié)構(gòu)楚殿、類(lèi)和枚舉都需要不同的代碼去完成這些繁多的任務(wù),比如說(shuō)查找子元素的數(shù)量, 比如針對(duì) OC, Swift 做不同的處理. 所有的函數(shù)因?yàn)樾枰煌念?lèi)型的檢查而需要派發(fā)不同的實(shí)現(xiàn)代碼.
為了解決這個(gè)問(wèn)題, Swift采用了一種類(lèi)似動(dòng)態(tài)派發(fā)的方式, 利用一個(gè)單獨(dú)的函數(shù)將 Swift 類(lèi)型映射成一個(gè) C++ 類(lèi)的實(shí)例. 在一個(gè)實(shí)例上調(diào)用方法然后派發(fā)合適的實(shí)現(xiàn).
映射的函數(shù)是 call().
template<typename F>
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
const F &f) -> decltype(f(nullptr)) { ... }
參數(shù):
-
passedValue
是實(shí)際需要傳入的Swift的值的指針. -
T
是該值的靜態(tài)類(lèi)型. 對(duì)應(yīng) Swift 中的范型參數(shù) <T>. -
passedType
是被顯式傳遞進(jìn) Swift 側(cè)并且會(huì)實(shí)際應(yīng)用在反射過(guò)程中的類(lèi)型(這個(gè)類(lèi)型和在使用 Mirror 作為父類(lèi)的實(shí)例在實(shí)際運(yùn)行時(shí)的對(duì)象類(lèi)型不一樣). -
f
參數(shù)會(huì)傳遞這個(gè)函數(shù)查找到的會(huì)被調(diào)用的實(shí)現(xiàn)的對(duì)象引用.
返回值:
這個(gè)函數(shù)會(huì)返回當(dāng)這個(gè) f
參數(shù)調(diào)用時(shí)的返回值.
call 的內(nèi)部實(shí)現(xiàn) 主要有兩部分:
針對(duì) Swift
auto call = [&](ReflectionMirrorImpl *impl) { ... }
針對(duì) OC
auto callClass = [&] { ... }
以及通過(guò) Switch 處理各種不同類(lèi)型的實(shí)現(xiàn).
callClass
內(nèi)部也會(huì)調(diào)用 call
, 因?yàn)?call
內(nèi)部用一個(gè) ReflectionMirrorImpl
的子類(lèi)實(shí)例去結(jié)束調(diào)用 f
赶盔,然后會(huì)調(diào)用這個(gè)實(shí)例上的方法去讓真正的工作完成.
auto call = [&](ReflectionMirrorImpl *impl) {
impl->type = type;
impl->value = value;
auto result = f(impl);
SWIFT_CC_PLUSONE_GUARD(T->vw_destroy(passedValue));
return result;
};
重點(diǎn)關(guān)注下 ReflectionMirrorImpl
的實(shí)現(xiàn).
// Abstract base class for reflection implementations.
struct ReflectionMirrorImpl {
const Metadata *type; 類(lèi)型信息
OpaqueValue *value; 值指針
virtual char displayStyle() = 0; 顯示方式
virtual intptr_t count() = 0; 子元素?cái)?shù)量
子元素信息
virtual AnyReturn subscript(intptr_t index, const char **outName,
void (**outFreeFunc)(const char *)) = 0;
virtual const char *enumCaseName() { return nullptr; }
#if SWIFT_OBJC_INTEROP
virtual id quickLookObject() { return nil; }
#endif
virtual ~ReflectionMirrorImpl() {}
};
關(guān)鍵: 作用在 Swift 和 C++ 組件之間的接口函數(shù)就會(huì)用 call 去調(diào)用相應(yīng)的方法.
比如前面提到的: swift_reflectionMirror_subscript
, 獲取子元素信息. 內(nèi)部就會(huì)調(diào)用
call(value, T, type, [&](ReflectionMirrorImpl *impl) {
return impl->subscript(index, outName, outFreeFunc);
});
大概有以下 5 種:
Tuple
, Struct
, Enum
等類(lèi)型都有對(duì)應(yīng)的 ReflectionMirrorImpl
的實(shí)現(xiàn).
下面會(huì)依次介紹元組的反射, 結(jié)構(gòu)體的反射, 類(lèi)的反射, 枚舉的反射, 其他種類(lèi).
元組的反射
元組的反射的實(shí)現(xiàn)
總體概覽:
struct TupleImpl : ReflectionMirrorImpl {
// 顯示方式, 元組是 't'
char displayStyle() { ... }
// 子元素的數(shù)量
intptr_t count() { ... }
// 子元素信息
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) { ... }
}
接下來(lái)從上往下看:
char displayStyle() {
return 't';
}
返回 't' 的顯示樣式來(lái)表明這是一個(gè)元組.
intptr_t count() {
auto *Tuple = static_cast<const TupleTypeMetadata *>(type);
return Tuple->NumElements;
}
count()
方法返回子元素的數(shù)量. type
由原來(lái)的 MetaType
類(lèi)型的指針轉(zhuǎn)為 TupleTypeMetadata
類(lèi)型的指針. TupleTypeMetadata
類(lèi)型有一個(gè)記錄元組的元素?cái)?shù)量的字段 NumElements
, 由此取值.
注意: TupleTypeMetadata
類(lèi)型實(shí)際是 TargetTupleTypeMetadata
類(lèi)型, 這是一個(gè) struct
, 內(nèi)部包含字段 NumElements
.
using TupleTypeMetadata = TargetTupleTypeMetadata<InProcess>;
subscript()
方法比較復(fù)雜.
auto *Tuple = static_cast<const TupleTypeMetadata *>(type);
- 獲取
type
的TupleTypeMetadata
類(lèi)型的指針.
if (i < 0 || (size_t)i > Tuple->NumElements)
swift::crash("Swift mirror subscript bounds check failure");
- 防止調(diào)用者請(qǐng)求了不存在的元組的索引.
i 的作用在于 可以檢索元素和對(duì)應(yīng)的名字.
- 對(duì)于元組而言, 這個(gè)名字是該元素在元組中的label, 若沒(méi)有l(wèi)abel, 默認(rèn)就是一個(gè) .0 的數(shù)值指示器.
- 對(duì)于結(jié)構(gòu)體或者類(lèi)來(lái)說(shuō), 這個(gè)名字是屬性名.
bool hasLabel = false;
if (const char *labels = Tuple->Labels) {
const char *space = strchr(labels, ' ');
for (intptr_t j = 0; j != i && space; ++j) {
labels = space + 1;
space = strchr(labels, ' ');
}
// If we have a label, create it.
if (labels && space && labels != space) {
*outName = strndup(labels, space - labels);
hasLabel = true;
}
}
- 查找元組中第 i 個(gè)位置的
label
.label
是以空格為間隔存儲(chǔ)在Tuple
中的labels
字段里.
strchr(s, 'c')
可以查找字符串 s
中首次出現(xiàn)字符 c
的位置.
返回首次出現(xiàn) 'c' 的位置的指針, 返回的地址是被查找字符串指針開(kāi)始的第一個(gè)與 'c' 相同字符的指針.
strndup(labels, space - labels)
將字符串拷貝到新建的位置處, 若不需要返回的字符串, 需要手動(dòng)調(diào)用 free
將其釋放.
if (!hasLabel) {
// The name is the stringized element number '.0'.
char *str;
asprintf(&str, ".%" PRIdPTR, i);
*outName = str;
}
- 如果沒(méi)有
label
, 則創(chuàng)建一個(gè)以.i
為名字的字符串為label
. 類(lèi)似下面這樣
let tuple = ("jack", "lily", "lucy")
print(tuple.0) // jack
*outFreeFunc = [](const char *str) { free(const_cast<char *>(str)); };
-
outFreeFunc
用于調(diào)用者手動(dòng)調(diào)用此函數(shù)來(lái)釋放返回的label
. 對(duì)應(yīng)前面的strndup
.
strdup()
在內(nèi)部調(diào)用了 malloc()
為變量分配內(nèi)存, 不需要使用返回的字符串時(shí), 需要用 free()
釋放相應(yīng)的內(nèi)存空間, 否則會(huì)造成內(nèi)存泄漏.
// Get the nth element.
auto &elt = Tuple->getElement(i);
auto *bytes = reinterpret_cast<const char *>(value);
auto *eltData = reinterpret_cast<const OpaqueValue *>(bytes + elt.Offset);
- 利用
getElement(i)
獲取Tuple
元數(shù)據(jù)的相關(guān)信息,elt
是一個(gè)Element
類(lèi)型的結(jié)構(gòu)體實(shí)例.
struct Element {
/// The type of the element.
ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> Type;
/// The offset of the tuple element within the tuple.
StoredSize Offset;
OpaqueValue *findIn(OpaqueValue *tuple) const {
return (OpaqueValue*) (((char*) tuple) + Offset);
}
};
elt
包含了一個(gè) offset
字段, 表示該元素在元組中的偏移值, 可以應(yīng)用在元組值上, 去獲得元素的值指針.
Any result;
result.Type = elt.Type;
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(eltData));
-
elt
還包含了元素的類(lèi)型, 通過(guò)類(lèi)型和值的指針斤程,去構(gòu)造一個(gè)包括這個(gè)值新的Any
對(duì)象.
return AnyReturn(result);
- 通過(guò)
AnyReturn
包裝, 返回子元素信息.AnyReturn
是一個(gè)struct
. 它可以保證即使在任何將在寄存器中返回 Any 的體系結(jié)構(gòu)中也是如此.
struct AnyReturn {
Any any;
AnyReturn(Any a) : any(a) { }
operator Any() { return any; }
~AnyReturn() { }
};
這里的 Any 指的是
/// The layout of Any.
using Any = OpaqueExistentialContainer;
在介紹結(jié)構(gòu)體, 類(lèi), 枚舉的反射時(shí), 先來(lái)看看一個(gè)函數(shù) swift_getFieldAt
, 這個(gè)函數(shù)可以通過(guò)用語(yǔ)言的元數(shù)據(jù)去查找類(lèi)型信息. HandyJSON
里面直接用到了.
swift_getFieldAt
swift_getFieldAt()
可以通過(guò)結(jié)構(gòu)、類(lèi)和枚舉的元數(shù)據(jù)去查找類(lèi)型信息
函數(shù)原型:
void swift::swift_getFieldAt(
const Metadata *base, unsigned index,
std::function<void(llvm::StringRef name, FieldType fieldInfo)>
callback) { ... }
接下來(lái)從上往下看.
auto *baseDesc = base->getTypeContextDescriptor();
if (!baseDesc)
return;
通過(guò)元數(shù)據(jù)獲取類(lèi)型的上下文描述
auto getFieldAt = [&](const FieldDescriptor &descriptor) { ... }
定義一個(gè)方法 getFieldAt
, 從描述符中查找信息.
接下來(lái)的工作分為兩步.
- 查找描述符.
- 調(diào)用
getFieldAt
方法, 通過(guò)描述符查找信息.
auto dem = getDemanglerForRuntimeTypeResolution();
獲取符號(hào)還原器, 將符號(hào)修飾過(guò)的類(lèi)名還原為實(shí)際的類(lèi)型引用.
auto &cache = FieldCache.get();
獲取字段描述符的緩存.
auto isRequestedDescriptor = [&](const FieldDescriptor &descriptor) {
assert(descriptor.hasMangledTypeName());
auto mangledName = descriptor.getMangledTypeName(0);
if (!_contextDescriptorMatchesMangling(baseDesc,
dem.demangleType(mangledName)))
return false;
cache.FieldCache.getOrInsert(base, &descriptor);
getFieldAt(descriptor);
return true;
};
定義一個(gè)方法, 檢查輸入的描述符是否是被需要的哪一個(gè), 如果是, 那么將描述符放到緩存中, 并且調(diào)用 getFieldAt
, 然后返回成功給調(diào)用者.
if (auto Value = cache.FieldCache.find(base)) {
getFieldAt(*Value->getDescription());
return;
}
如果存在字段描述符緩存, 那么通過(guò) getFieldAt
獲取字段信息.
ScopedLock guard(cache.SectionsLock);
// Otherwise let's try to find it in one of the sections.
for (auto §ion : cache.DynamicSections) {
for (const auto *descriptor : section) {
if (isRequestedDescriptor(*descriptor))
return;
}
}
for (const auto §ion : cache.StaticSections) {
for (auto &descriptor : section) {
if (isRequestedDescriptor(descriptor))
return;
}
}
字段描述符可以在運(yùn)行時(shí)注冊(cè), 也可以在編譯時(shí)加入到二進(jìn)制文件中. 這兩個(gè)循環(huán)查找所有已知的字段描述符以進(jìn)行匹配.
接下來(lái)看看 getFieldAt
內(nèi)部的實(shí)現(xiàn)過(guò)程.
getFieldAt
這個(gè)方法作用是將字段描述符轉(zhuǎn)化為名字和字段類(lèi)型, 進(jìn)行回調(diào)返回.
auto &field = descriptor.getFields()[index];
- 獲取字段的引用.
auto name = field.getFieldName(0);
- 在引用中獲取字段的名字.
if (!field.hasMangledTypeName()) {
callback(name, FieldType().withIndirect(field.isIndirectCase()));
return;
}
- 判斷是否有類(lèi)型. 比如, 字段實(shí)際上是一個(gè)枚舉, 那么它可能沒(méi)有類(lèi)型.
std::vector<const ContextDescriptor *> descriptorPath;
{
const auto *parent = reinterpret_cast<
const ContextDescriptor *>(baseDesc);
while (parent) {
if (parent->isGeneric())
descriptorPath.push_back(parent);
parent = parent->Parent.get();
}
}
- 定義一個(gè)
ContextDescriptor
類(lèi)型的指針descriptorPath
, 通過(guò)baseSesc
獲取描述符的路徑. 也就是將這個(gè)類(lèi)型的所有范型的上下文抽離出來(lái).
auto typeInfo = _getTypeByMangledName(
field.getMangledTypeName(0),
[&](unsigned depth, unsigned index) -> const Metadata * { ... }
- 獲取類(lèi)型信息
前面有提到, 字段的引用 field
將字段類(lèi)型儲(chǔ)存為一個(gè)符號(hào)修飾的名字, 但是最終回調(diào)的是元數(shù)據(jù)的指針. 所以需要將符號(hào)修飾的名字轉(zhuǎn)化為一個(gè)真實(shí)的類(lèi)型. (字符串 -> 類(lèi)型)
_getTypeByMangledName
方法的作用在此.
在 _getTypeByMangledName
內(nèi)部,
field.getMangledTypeName(0)
首先傳入由符號(hào)修飾的類(lèi)型.
if (depth >= descriptorPath.size())
return nullptr;
接著檢查請(qǐng)求的深度與描述符的路徑, 如果前者比后者大, 返回失敗
unsigned currentDepth = 0;
unsigned flatIndex = index;
const ContextDescriptor *currentContext = descriptorPath.back();
for (const auto *context : llvm::reverse(descriptorPath)) {
if (currentDepth >= depth)
break;
flatIndex += context->getNumGenericParams();
currentContext = context;
++currentDepth;
}
接著, 從字段的類(lèi)型中獲取范型參數(shù). 將索引和深度轉(zhuǎn)化為單獨(dú)的扁平化的索引, 通過(guò)遍歷描述符的路徑, 在每個(gè)階段添加范型參數(shù)的數(shù)量直到達(dá)到深度為止.
if (index >= currentContext->getNumGenericParams())
return nullptr;
如果索引比范型參數(shù)可達(dá)到的深度大乖酬,那么失敗.
return base->getGenericArgs()[flatIndex];
在 _getTypeByMangledName
的最后, 從元數(shù)據(jù) base
獲得基本類(lèi)型信息, 再在其中獲得合適的范型參數(shù).
callback(name, FieldType()
.withType(typeInfo)
.withIndirect(field.isIndirectCase())
.withWeak(typeInfo.isWeak()));
getFieldAt
方法中最重要的一步, 執(zhí)行回調(diào), 將字段名字和類(lèi)型暴露出來(lái).
結(jié)構(gòu)體的反射
結(jié)構(gòu)體的反射的實(shí)現(xiàn)和元組類(lèi)似, 但是結(jié)構(gòu)體可能包含需要反射代碼去提取的弱引用. 下面是實(shí)現(xiàn)代碼.
struct StructImpl : ReflectionMirrorImpl {
顯示方式, 結(jié)構(gòu)體是 's'
char displayStyle() { ... }
子元素?cái)?shù)量
intptr_t count() { ... }
所有子元素信息
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) { ... }
}
char displayStyle() {
return 's';
}
結(jié)構(gòu)體的顯示樣式是 's'
intptr_t count() {
auto *Struct = static_cast<const StructMetadata *>(type);
return Struct->getDescription()->NumFields;
}
count
方法返回子元素的數(shù)量. type
由原來(lái)的 MetaType
類(lèi)型的指針轉(zhuǎn)為 StructMetadata
類(lèi)型的指針.
StructMetadata
類(lèi)型有一個(gè) TargetStructDescriptor<Runtime>
類(lèi)型的字段 getDescription()
, 這是一個(gè)指針, TargetStructDescriptor
類(lèi)中有一個(gè)字段 NumFields
, 由此可獲得子元素?cái)?shù)量.
注意: StructMetadata
類(lèi)型實(shí)際是 TargetStructMetadata
類(lèi)型, 這是一個(gè) struct
using StructMetadata = TargetStructMetadata<InProcess>;
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) { ... }
subscript
方法比較復(fù)雜
auto *Struct = static_cast<const StructMetadata *>(type);
- 獲取
type
的StructMetadata
類(lèi)型的指針.
if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
- 進(jìn)行邊界檢查, 防止訪問(wèn)不存在的子元素.
auto fieldOffset = Struct->getFieldOffsets()[i];
- 查找對(duì)應(yīng)索引的字段偏移值.
Any result;
swift_getFieldAt(type, i, [&](llvm::StringRef name, FieldType fieldInfo) {
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
獲取字段名字
*outName = name.data();
*outFreeFunc = nullptr;
計(jì)算字段儲(chǔ)存的指針
auto *bytes = reinterpret_cast<char*>(value);
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
loadSpecialReferenceStorage 方法用于處理將字段的值復(fù)制到 Any 返回值以處理弱引用
bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
如果值沒(méi)有被載入的話那么那個(gè)值用普通的儲(chǔ)存死相,并且以普通的方式拷貝到返回值
if (!didLoad) {
result.Type = fieldInfo.getType();
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(fieldData));
}
});
- 通過(guò)
_swift_getFieldAt
方法, 獲取結(jié)構(gòu)體字段中的信息(字段的名字和類(lèi)型).
AnyReturn(result);
最后, 將子元素信息返回.
類(lèi)的反射
struct ClassImpl : ReflectionMirrorImpl {
顯示樣式, 類(lèi)是 'c'
char displayStyle() { ... }
子元素?cái)?shù)量
intptr_t count() { ... }
子元素信息
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) { ... }
#if SWIFT_OBJC_INTEROP
id quickLookObject() { ... }
#endif
}
StructImpl
與 ClassImpl
的實(shí)現(xiàn)主要有兩個(gè)不同:
第一, ClassImpl
實(shí)現(xiàn)了 quickLookObject
這個(gè)字段, 如果父類(lèi)是 OC 中的類(lèi)的話, 在使用 quickLookObject
時(shí)會(huì)調(diào)起 OC 的 debugQuickLookObject
方法.
#if SWIFT_OBJC_INTEROP
id quickLookObject() {
id object = [*reinterpret_cast<const id *>(value) retain];
if ([object respondsToSelector:@selector(debugQuickLookObject)]) {
id quickLookObject = [object debugQuickLookObject];
[quickLookObject retain];
[object release];
return quickLookObject;
}
return object;
}
#endif
第二, 如果該類(lèi)的父類(lèi)是 OC 的類(lèi),字段的偏移值需要在 OC 運(yùn)行時(shí)獲得.
uintptr_t fieldOffset;
if (usesNativeSwiftReferenceCounting(Clas)) {
fieldOffset = Clas->getFieldOffsets()[i];
} else {
#if SWIFT_OBJC_INTEROP
Ivar *ivars = class_copyIvarList((Class)Clas, nullptr);
fieldOffset = ivar_getOffset(ivars[i]);
free(ivars);
#else
swift::crash("Object appears to be Objective-C, but no runtime.");
#endif