前言
上篇Swift Mirror & Error主要是講解了Mirror的一個(gè)常見(jiàn)的應(yīng)用場(chǎng)景:JSON解析,但是里面的原理是怎樣的?底層源碼流程是如何處理反射呢?本篇文章將為大家詳細(xì)解析Mirror的底層實(shí)現(xiàn)流程。
一、Mirror架構(gòu)大致分析
首先我們大致來(lái)看看Mirror的架構(gòu),大概有哪些部分構(gòu)成??
-
Mirror.swift源碼路徑??
swift->stdlib->public->core->Mirror.swift

2.與反射相關(guān)的API
ReflectionMirror.swift

ReflectionMirror.mm

其中,ReflectionMirror.swift中定義的函數(shù),會(huì)通過(guò)@_silgen_name修飾符,這個(gè)修飾符的作用就是Swift編譯器會(huì)將該修飾符修飾的函數(shù)符號(hào)映射成C++的函數(shù)符號(hào)。
@_silgen_name示例
通常,我們?cè)趕wift的工程中想調(diào)用C/C++的函數(shù),一般是這樣處理(我們以C函數(shù)為例看看):
- 先在.h中聲明c函數(shù),在.c中實(shí)現(xiàn)


- 在橋接.h文件中引入C函數(shù)的頭文件.h

- 在.swift中使用C函數(shù)

其實(shí),我們也可以省去第2步,在.swift中使用@_silgen_name修飾符??
@_silgen_name("add")
func swift_add(_ a :Int32, _ b :Int32) -> Int32
var value = swift_add(10, 20)
print(value)

二、Mirror底層流程解析
接下來(lái),我們看看Mirror的源碼??

接著,我們看internalReflecting源碼,搜索internalReflecting,發(fā)現(xiàn)是在ReflectionMirror.swift中??

2.1 internalReflecting源碼分析
再來(lái)看初始化internalReflecting源碼中調(diào)用的幾個(gè)關(guān)鍵函數(shù):
_getNormalizedType
根據(jù)上面對(duì)Mirror的初始化函數(shù)的分析得知,_getNormalizedType是獲取當(dāng)前對(duì)象的類型??
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
對(duì)應(yīng)的C++函數(shù)是swift_reflectionMirror_normalizedType??
// func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}
調(diào)用的是call。
getChild
再來(lái)看getChild,即獲取屬性值??
internal func getChild<T>(of value: T, type: Any.Type, index: Int) -> (label: String?, value: Any) {
var nameC: UnsafePointer<CChar>? = nil
var freeFunc: NameFreeFunc? = nil
let value = _getChild(of: value, type: type, index: index, outName: &nameC, outFreeFunc: &freeFunc)
let name = nameC.flatMap({ String(validatingUTF8: $0) })
freeFunc?(nameC)
return (name, value)
}
其中最關(guān)鍵的就是let value = _getChild(of: value, type: type, index: index, outName: &nameC, outFreeFunc: &freeFunc),繼續(xù)看看_getChild??
@_silgen_name("swift_reflectionMirror_subscript")
internal func _getChild<T>(
of: T,
type: Any.Type,
index: Int,
outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any
同理,所對(duì)應(yīng)的C++函數(shù)是swift_reflectionMirror_subscript??
// func _getChild<T>(
// of: T,
// type: Any.Type,
// index: Int,
// outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
// outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
// ) -> Any
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
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);
});
}
最終也是調(diào)用的call。
_getDisplayStyle
_getDisplayStyle是獲取當(dāng)前對(duì)象subject的顯示類型,源碼如下??
@_silgen_name("swift_reflectionMirror_displayStyle")
internal func _getDisplayStyle<T>(_: T) -> CChar
同理,搜索swift_reflectionMirror_displayStyle??
// func _getDisplayStyle<T>(_: T) -> CChar
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
char swift_reflectionMirror_displayStyle(OpaqueValue *value, const Metadata *T) {
return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->displayStyle(); });
}
還是call。
最關(guān)鍵的call函數(shù)
call函數(shù)的源碼很長(zhǎng),我們一部分一部分的看??
- 入?yún)?& 返回值
template<typename F>
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
const F &f) -> decltype(f(nullptr))
-
passedValue?? 一個(gè)指針,指向swift調(diào)用方傳遞來(lái)的值 -
T?? 該值的靜態(tài)類型 -
passedType??顯式傳入的且在反射過(guò)程中的用到的類型 -
f?? 傳遞被查找到的會(huì)被調(diào)用的實(shí)現(xiàn)的引用對(duì)象,可以理解是個(gè)閉包的引用對(duì)象 -
返回值?? 返回f參數(shù)調(diào)用后的返回值
- 部分一:確定反射的真實(shí)類型

其中unwrapExistential源碼(其實(shí)就是強(qiáng)制類型轉(zhuǎn)換,并取值)??

ReflectionMirrorImpl后面再分析。
- 部分二:針對(duì)【類對(duì)象】的處理

*部分三:其它類型的處理

以上就是對(duì)call函數(shù)源碼的大致流程的分析,最關(guān)鍵的一步就是使用ReflectionMirrorImpl子類的實(shí)例去調(diào)用f,然后封裝成一個(gè)匿名函數(shù)call(類似于閉包),再根據(jù)type對(duì)應(yīng)的類型type->getKind()去走真正的反射流程。
2.2 調(diào)試驗(yàn)證:_getNormalizedType
上面的源碼看起來(lái)是不是有些費(fèi)勁,沒(méi)關(guān)系,接下來(lái)我們來(lái)斷點(diǎn)調(diào)試一下_getNormalizedType函數(shù),看看傳遞的入?yún)⒕唧w是什么?
先分別給swift_reflectionMirror_normalizedType和call打上斷點(diǎn),如下圖所示:


運(yùn)行源碼,再準(zhǔn)備調(diào)試示例代碼,輸入到終端??
class LGTeacher{var age = 18}
var t = LGTeacher()
let mirror = Mirror(reflecting: t)
觸發(fā)斷點(diǎn)如下圖??(其中var t = LGTeacher()這句也會(huì)觸發(fā),直接跳過(guò))


注意:swift源碼調(diào)試起來(lái)很卡,經(jīng)常容易中斷??
2.3 ReflectionMirrorImpl 反射子類
ReflectionMirrorImpl的子類主要有以下幾種:
-
TupleImpl元組的反射 -
StructImpl結(jié)構(gòu)體的反射 -
EnumImpl枚舉的反射 -
ClassImpl類的反射 -
MetatypeImpl元數(shù)據(jù)的反射 -
OpaqueImpl不透明類型的反射
首先查看ReflectionMirrorImpl的底層定義

我們以類ClassImpl為例,看看??




類ClassImpl與其它數(shù)據(jù)結(jié)構(gòu)的不同在于,需要考慮繼承鏈關(guān)系,于是多出了父類遞歸處理的一些函數(shù)。其實(shí)仔細(xì)看看類ClassImpl反射子類中對(duì)屬性的操作處理,都是先找到metadata,然后找到其description,再根據(jù)偏移值fieldOffset,就可得到真正索引i對(duì)應(yīng)的字段(即屬性)。
ClassMetadata
其中,類Class的metadata類型就是ClassMetadata??

而ClassMetadata定義??
using ClassMetadata = TargetClassMetadata<InProcess>;
??
struct TargetClassMetadata : public TargetAnyClassMetadata<Runtime> {
...
}
??
struct TargetAnyClassMetadata : public TargetHeapMetadata<Runtime> {
...
}
??
struct TargetHeapMetadata : TargetMetadata<Runtime> {
...
}
根據(jù)繼承鏈,最終定位到我們熟悉的TargetMetadata,之前在Swift編譯流程 & Swift類中分析過(guò),TargetMetadata中有一個(gè)屬性kind(相當(dāng)于OC中的isa),而TargetClassMetadata除了擁有父類的kind,還有一個(gè)description,用于記錄元數(shù)據(jù)的描述??

TargetClassDescriptor
接著來(lái)到TargetClassDescriptor??

類
TargetClassDescriptor有關(guān)鍵的兩個(gè)成員變量NumFields 和FieldOffsetVectorOffset,同時(shí)繼承鏈的父類包含TargetTypeContextDescriptor??


繼續(xù)沿著繼承鏈向上查找,來(lái)到TargetContextDescriptor??
template <typename Runtime>
class TargetTypeContextDescriptor : public TargetContextDescriptor<Runtime>
其中包含2個(gè)重要成員變量Flags 和 Parent??

至此,結(jié)合上面的對(duì)ClassMetadata 和 TargetClassDescriptor這兩個(gè)關(guān)鍵類型的分析,我們?cè)诜瓷渲袑?duì)屬性的處理是通過(guò)getFieldAt函數(shù)??

上圖可知,getFieldAt中是通過(guò)Metadata獲取Fields字段,進(jìn)而getFieldName得到字段名稱,而Fields的類型TargetRelativeDirectPointer,其內(nèi)部的描述信息類型是FieldDescriptor。
偏移量的計(jì)算
上述已拿到了屬性名稱,剩下的就是屬性值的處理,上述已經(jīng)分析過(guò),屬性的值是通過(guò)偏移量相加來(lái)計(jì)算的,而這個(gè)偏移量也是存儲(chǔ)在TargetRelativeDirectPointer指針中(也是Fields中),同理,根據(jù)繼承鏈,向上查找??
using TargetRelativeDirectPointer
= typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
??
class RelativeDirectPointer<T, Nullable, Offset,
typename std::enable_if<!std::is_function<T>::value>::type>
: private RelativeDirectPointerImpl<T, Nullable, Offset> {
...
}
??
template<typename T, bool Nullable, typename Offset>
class RelativeDirectPointerImpl {
private:
/// The relative offset of the function's entry point from *this.
Offset RelativeOffset;
...
}
最終定位到屬性RelativeOffset,用于表示屬性的相對(duì)偏移值,而不是直接存儲(chǔ)地址,如下圖所示??

偏移的計(jì)算相關(guān)的底層源碼??
using ValueTy = T;
using PointerTy = T*;
PointerTy get() const & {
// Check for null.
if (Nullable && RelativeOffset == 0)
return nullptr;
// The value is addressed relative to `this`.
uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
return reinterpret_cast<PointerTy>(absolute);
}
// 其中,applyRelativeOffset的源碼 ??
template<typename BasePtrTy, typename Offset>
static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
static_assert(std::is_integral<Offset>::value &&
std::is_signed<Offset>::value,
"offset type should be signed integer");
// 指針地址
auto base = reinterpret_cast<uintptr_t>(basePtr);
// We want to do wrapping arithmetic, but with a sign-extended
// offset. To do this in C, we need to do signed promotion to get
// the sign extension, but we need to perform arithmetic on unsigned values,
// since signed overflow is undefined behavior.
auto extendOffset = (uintptr_t)(intptr_t)offset;
// 指針地址+存放的offset(偏移地址) --> 內(nèi)存平移獲取值
return base + extendOffset;
}
FieldDescriptor類:存放屬性
最后我們來(lái)看看FieldDescriptor的源碼??
class FieldDescriptor {
const FieldRecord *getFieldRecordBuffer() const {
return reinterpret_cast<const FieldRecord *>(this + 1);
}
public:
const RelativeDirectPointer<const char> MangledTypeName;
const RelativeDirectPointer<const char> Superclass;
......
const FieldDescriptorKind Kind;
const uint16_t FieldRecordSize;
const uint32_t NumFields;
......
// 獲取所有屬性,每個(gè)屬性用FieldRecord封裝
llvm::ArrayRef<FieldRecord> getFields() const {
return {getFieldRecordBuffer(), NumFields};
}
......
}
其中,FieldRecord是對(duì)屬性的一個(gè)封裝,定義??
class FieldRecord {
const FieldRecordFlags Flags;
public:
const RelativeDirectPointer<const char> MangledTypeName;
const RelativeDirectPointer<const char> FieldName;
三、仿寫Mirror
以上主要分析了類Class通過(guò)Mirror反射獲取屬性和值,還有涉及的重要的類和結(jié)構(gòu)體的相關(guān)源碼?,F(xiàn)在我們以結(jié)構(gòu)體為例,仿寫Mirror代碼??
// 結(jié)構(gòu)體類型
struct StructMetadata {
var kind: Int
var description: UnsafeMutablePointer<StructMetadataDesc>
}
// 結(jié)構(gòu)體類型的描述
struct StructMetadataDesc {
var flags: UInt32
var parent: UInt32 // 展示用Uint32代替,實(shí)際是相同大小的結(jié)構(gòu)體,
var name: RelativeDirectPointer<CChar> // 不在乎具體類型,就先用UnsafeRawPointer
var accessFunctionPtr: RelativeDirectPointer<UnsafeRawPointer> // 不在乎具體類型,就先用UnsafeRawPointer
var fields: RelativeDirectPointer<FieldDescription> // 記錄所有屬性內(nèi)容
var numFields: UInt32 // 屬性個(gè)數(shù)
var fieldOffsetVectorOffset: UInt32
}
// 記錄結(jié)構(gòu)體內(nèi)所有屬性的結(jié)構(gòu)
struct FieldDescription {
var MangledTypeName: RelativeDirectPointer<CChar>
var Superclass: RelativeDirectPointer<CChar>
var Kind: UInt16
var FieldRecordSize: UInt16
var NumFields: UInt32
var fields: FieldRecord // 連續(xù)存儲(chǔ)空間 (有幾個(gè)數(shù)據(jù),就會(huì)在后面添加幾個(gè)記錄,通過(guò)內(nèi)存平移讀取)
}
// 每個(gè)屬性的內(nèi)容
struct FieldRecord {
var flag: Int32
var mangledTypeName: RelativeDirectPointer<CChar>
var fieldName: RelativeDirectPointer<CChar> // 屬性名稱
}
// 相對(duì)位移指針
struct RelativeDirectPointer<T>{
var offset: Int32
// 偏移offset位置,獲取內(nèi)容指針
mutating func get() -> UnsafeMutablePointer<T> {
let offset = self.offset
// withUnsafePointer獲取指針
return withUnsafePointer(to: &self) { p in
// UnsafeMutablePointer 返回T類型對(duì)象的指針
// UnsafeRawPointer將p指針轉(zhuǎn)換為未知類型
// numericCast將offset轉(zhuǎn)換為偏移單位數(shù)
// advanced進(jìn)行內(nèi)存偏移
// assumingMemoryBound綁定指針為T類型
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))
}
}
}
struct LGTeacher {
var age = 18
var name = "Luoji"
}
// 讀取將LGTeacher指針內(nèi)容,賦值給StructMetadata (unsafeBitCast: 通過(guò)字節(jié)讀取)
let p = unsafeBitCast(LGTeacher.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)
// 讀取當(dāng)前name的內(nèi)容指針
let namePtr = p.pointee.description.pointee.name.get()
let count = p.pointee.description.pointee.numFields
print("類型:\(String(cString: namePtr))") // name是CChar類型,轉(zhuǎn)為字符串輸出
print("屬性個(gè)數(shù):\(count)")
// 單獨(dú)讀取第一個(gè)屬性名
var fields = p.pointee.description.pointee.fields.get()
let fieldRecord1Name = fields.pointee.fields.fieldName.get()
print(String(cString: fieldRecord1Name))
// 讀取所有記錄
print("----讀取所有屬性名----")
(0..<count).forEach { index in
let recordPtr = withUnsafePointer(to: &fields.pointee.fields) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: FieldRecord.self).advanced(by: Int(index)))
}
print(String(cString: recordPtr.pointee.fieldName.get()))
}
print("----dump----")
dump(LGTeacher()) // 相似的實(shí)現(xiàn)方式
總結(jié)
綜上所述,Mirror反射干的事情大致分為三步:
- Mirror在實(shí)例對(duì)象的
metadata中找到Descriptor - 在
Descriptor中
2.1 找到name,獲取類型(相當(dāng)于type名稱)
2.2 找到numFields,獲取屬性個(gè)數(shù) - 找到
FieldDescriptor中的fields,來(lái)找到對(duì)當(dāng)前屬性的描述,然后通過(guò)指針內(nèi)存平移,獲取其他屬性
下圖是以類為例,底層Mirror反射的流程圖??
