本文主要是分析Mirror的底層實(shí)現(xiàn),以及根據(jù)Mirror底層原理仿寫其結(jié)構(gòu)的實(shí)現(xiàn)
在Swift-進(jìn)階:反射Mirror & 錯(cuò)誤處理文章中青自,我們介紹了Mirror的使用,即JSON解析矫膨,對(duì)此我們有如下一些疑問:
1妖混、系統(tǒng)是如何通過
Mirror
獲取對(duì)應(yīng)的屬性以及值的萍恕?2、Swift眾所周知是一門靜態(tài)語言蟀拷,系統(tǒng)在底層到底做了什么碰纬,使swift具有了反射的特性呢?
下面我們來對(duì)Mirror的底層實(shí)現(xiàn)進(jìn)行探索
Mirror底層源碼分析
反射的API
主要是由兩部分實(shí)現(xiàn)的
一部分是通過Swift實(shí)現(xiàn)问芬,即
ReflectionMirror.swift
一部分是通過C++實(shí)現(xiàn)悦析,即
ReflectionMirror.mm
兩者之間是通過暴露給swift的C++函數(shù)進(jìn)行通信,即
@_silgen_name
修飾符會(huì)通知swift編譯器將這個(gè)swift函數(shù)映射成C++函數(shù)的符號(hào)Mirror的源碼是在
Mirror.swift
文件中,路徑為swift->stdlib->public->core->Mirror.swift
swift 使用技巧
使用@_silgen_name
關(guān)鍵字聲明的方法此衅,實(shí)際調(diào)用是括號(hào)中的方法强戴,例如swift_cjl_add
實(shí)際調(diào)用的是c中的cjl_add
- 通過C定義一個(gè)方法亭螟,在swift中使用
<!--1、定義c方法-->
//.h聲明
int cjl_add(int a, int b);
//.c中實(shí)現(xiàn)
int cjl_add(int a, int b){
return a+b;
}
<!--2骑歹、橋接文件中引入頭文件-->
#import "test.h"
<!--3预烙、swift使用-->
var value = cjl_add(10, 20)
print(value)
<!--4、打印結(jié)果-->
30
- 可以將上述代碼中的第2步去掉刪除道媚,采用
@_silgen_name
關(guān)鍵字
<!--1扁掸、swift中針對(duì)cjl_add方法的聲明-->
//通過@_silgen_name聲明
@_silgen_name("cjl_add")
func swift_cjl_add(_ a: Int32, _ b: Int32) -> Int32
<!--2、使用-->
var value = swift_cjl_add(20, 30)
print(value)
<!--3最域、打印結(jié)果-->
50
分析Mirror
-
在
Mirror.swift
文件中找到Mirror
谴分,是一個(gè)結(jié)構(gòu)體類型 查找其初始化方法
public init(reflecting subject: Any)
public init(reflecting subject: Any) {
//判斷 subject 是否符合 CustomReflectable動(dòng)態(tài)類型
if case let customized as CustomReflectable = subject {
//如果符合,則由 customMirror 確定屬性
self = customized.customMirror
} else {
//如果不符合镀脂,則由語言生成
self = Mirror(internalReflecting: subject)
}
}
- 查找
internalReflecting
方法(路徑為swift->stdlib->public->core->ReflectionMirror.swift
)
extension Mirror {
// Mirror的初始化器中檢索需要的信息
/*
- subject 將要被反射的值
- subjectType 將要被反射的subject值的類型牺蹄,通常是值的運(yùn)行時(shí)類型
-
*/
internal init(internalReflecting subject: Any,
subjectType: Any.Type? = nil,
customAncestor: Mirror? = nil)
{
//根據(jù)_getNormalizedType獲取傳入的subject的真正類型,其中type(of: subject)獲取的動(dòng)態(tài)類型
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
// 獲取屬性大小
let childCount = _getChildCount(subject, type: subjectType)
// 遍歷薄翅,將屬性存儲(chǔ)到字典中
let children = (0 ..< childCount).lazy.map({
// getChild函數(shù)時(shí)C++的_getChild 函數(shù)的簡(jiǎn)單封裝沙兰,將標(biāo)簽名字中包含的C字符串轉(zhuǎn)換為Swift字符串
getChild(of: subject, type: subjectType, index: $0)
})
// 賦值給Mirror的屬性children
self.children = Children(children)
// 設(shè)置父類反射
self._makeSuperclassMirror = {//按需求構(gòu)建父類的Mirror的閉包
// 獲取傳入對(duì)象的類
guard let subjectClass = subjectType as? AnyClass,
// 獲取父類
let superclass = _getSuperclass(subjectClass) else {
return nil//非類的類型、沒有父類的類的Mirror匿刮,會(huì)獲取到nil
}
// 調(diào)用者可以用一個(gè)可作為父類的Mirror直接返回Mirror實(shí)例來指定自定義的祖先的表現(xiàn)
// Handle custom ancestors. If we've hit the custom ancestor's subject type,
// or descendants are suppressed, return it. Otherwise continue reflecting.
if let customAncestor = customAncestor {
if superclass == customAncestor.subjectType {
return customAncestor
}
if customAncestor._defaultDescendantRepresentation == .suppressed {
return customAncestor
}
}
// 給相同值返回一個(gè)將 superclass作為 subjectType的新的Mirror
return Mirror(internalReflecting: subject,
subjectType: superclass,
customAncestor: customAncestor)
}
// 獲取并解析顯示的樣式僧凰,并設(shè)置Mirror的其他屬性
let rawDisplayStyle = _getDisplayStyle(subject)
switch UnicodeScalar(Int(rawDisplayStyle)) {
case "c": self.displayStyle = .class
case "e": self.displayStyle = .enum
case "s": self.displayStyle = .struct
case "t": self.displayStyle = .tuple
case "\0": self.displayStyle = nil
default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
}
self.subjectType = subjectType
self._defaultDescendantRepresentation = .generated
}
// 快速查找
internal static func quickLookObject(_ subject: Any) -> _PlaygroundQuickLook? {
#if _runtime(_ObjC)
let object = _getQuickLookObject(subject)
return object.flatMap(_getClassPlaygroundQuickLook)
#else
return nil
#endif
}
}
??
<!--superclassMirror屬性的底層返回-->
public var superclassMirror: Mirror? {
return _makeSuperclassMirror()
}
nternal let _makeSuperclassMirror: () -> Mirror?
1探颈、通過
_getNormalizedType
獲取傳入的subject的真正類型
2熟丸、通過_getChildCount
方法獲取類中的屬性個(gè)數(shù)
3、遍歷屬性伪节,通過getChild
方法(C++的_getChild
函數(shù)的簡(jiǎn)單封裝)將標(biāo)簽名字中包含的C字符串轉(zhuǎn)換為Swift字符串光羞,并將屬性存儲(chǔ)到字典中,賦值給Mirror的屬性children
4怀大、Mirror有一個(gè)屬性superclassMirror
纱兑,會(huì)返回該類的父類,其底層是返回一個(gè)_makeSuperclassMirror
屬性化借,用于保存父類的Mirror閉包潜慎。首先會(huì)通過subjectType
獲取父類,然后按照需求構(gòu)建父類的Mirror閉包蓖康,如果是非類的類型铐炫、沒有父類的類
的Mirror,會(huì)獲取到nil
蒜焊。反之倒信,則直接返回一個(gè)可作為父類的Mirror的實(shí)例對(duì)象。
5泳梆、獲取并解析顯示的樣式鳖悠,并設(shè)置Mirror的其他屬性
- 進(jìn)入
_getNormalizedType
的實(shí)現(xiàn)榜掌,根據(jù)定義,最終會(huì)調(diào)用C++中的swift_reflectionMirror_normalizedType -> Call
方法
@_silgen_name("swift_reflectionMirror_normalizedType")
internal 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; });
}
??
/*
- passedValue 實(shí)際需要傳入的swift的值的指針
- T 該值的靜態(tài)類型
- passedType 被顯式傳入且會(huì)用在反射過程中的類型
- f 傳遞被查找到的會(huì)被調(diào)用的實(shí)現(xiàn)的對(duì)象引用
- 返回值:返回f參數(shù)調(diào)用時(shí)的返回值
*/
template<typename F>
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
const F &f) -> decltype(f(nullptr))
{
// 獲取type
const Metadata *type;
OpaqueValue *value;
std::tie(type, value) = unwrapExistential(T, passedValue);
// 判斷傳入type是否為空乘综,如果不為空憎账,則直接賦值給type
if (passedType != nullptr) {
type = passedType;
}
// 使用 ReflectionMirrorImpl 子類的實(shí)例去結(jié)束調(diào)用f,然后會(huì)調(diào)用這個(gè)實(shí)例上的方法去真正的工作完成
auto call = [&](ReflectionMirrorImpl *impl) {
// 返回的type是傳入非type
impl->type = type;
impl->value = value;
auto result = f(impl);
return result;
};
.....
switch (type->getKind()) {
case MetadataKind::Tuple: {//元組
......
}
case MetadataKind::Struct: {//結(jié)構(gòu)體
......
}
case MetadataKind::Enum://枚舉
case MetadataKind::Optional: {//可選
......
}
......
}
??
<!--unwrapExistential實(shí)現(xiàn)-->
static std::tuple<const Metadata *, OpaqueValue *>
unwrapExistential(const Metadata *T, OpaqueValue *Value) {
// If the value is an existential container, look through it to reflect the
// contained value.如果該值是一個(gè)存在的容器卡辰,請(qǐng)查看它以反映包含的值鼠哥。
// TODO: Should look through existential metatypes too, but it doesn't
// really matter yet since we don't have any special mirror behavior for
// concrete metatypes yet.
while (T->getKind() == MetadataKind::Existential) {
auto *existential
= static_cast<const ExistentialTypeMetadata *>(T);
// Unwrap the existential container.打開存在容器
T = existential->getDynamicType(Value);
Value = existential->projectValue(Value);
// Existential containers can end up nested in some cases due to generic
// abstraction barriers. Repeat in case we have a nested existential.
}
return std::make_tuple(T, Value);
}
??
<!--getDynamicType的實(shí)現(xiàn)-->
template<> const Metadata *
ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const {
// 根據(jù) 獲取此存在類型使用的表示形式 判斷
switch (getRepresentation()) {
case ExistentialTypeRepresentation::Class: {
auto classContainer =
reinterpret_cast<const ClassExistentialContainer*>(container);
void *obj = classContainer->Value;
return swift_getObjectType(reinterpret_cast<HeapObject*>(obj));
}
case ExistentialTypeRepresentation::Opaque: {
auto opaqueContainer =
reinterpret_cast<const OpaqueExistentialContainer*>(container);
return opaqueContainer->Type;
}
case ExistentialTypeRepresentation::Error: {
const SwiftError *errorBox
= *reinterpret_cast<const SwiftError * const *>(container);
return errorBox->getType();
}
}
swift_runtime_unreachable(
"Unhandled ExistentialTypeRepresentation in switch.");
}
call
中主要是一個(gè)大型switch
聲明和一些額外的代碼去處理特殊的情況,主要是會(huì)ReflectionMirrorImpl
的子類實(shí)例
去結(jié)束調(diào)用 f
看政,然后會(huì)調(diào)用這個(gè)實(shí)例上的方法去讓真正的工作完成朴恳。
1、首先根據(jù)
unwrapExistential
獲取type類型允蚣,其依賴于metaData
元數(shù)據(jù)
2于颖、判斷傳入的passedType
是否為空,如果不為空嚷兔,則直接賦值給type
3森渐、使用ReflectionMirrorImpl
子類的實(shí)例去結(jié)束調(diào)用f
,然后會(huì)調(diào)用這個(gè)實(shí)例上的方法去真正的工作完成
swift-source源碼調(diào)試_getNormalizedType方法
- 運(yùn)行swift源碼冒晰,在
Call
函數(shù)的第一行加斷點(diǎn) - 在源碼終端依次輸入下面代碼
class CJLTeacher{var age = 18}
var t = CJLTeacher()
let mirror = Mirror(reflecting: t)
運(yùn)行結(jié)果如下同衣,會(huì)在call的調(diào)用處斷住
其中參數(shù)的調(diào)試結(jié)果如下:
其中
value
是Mirror
實(shí)例type
是type(of:)
獲取的類型-
T
是自己傳入的類型
ReflectionMirrorImpl 反射基類
ReflectionMirrorImpl
的種類主要有以下幾種:
TupleImpl 元組的反射
StructImpl 結(jié)構(gòu)體的反射
EnumImpl 枚舉的反射
ClassImpl 類的反射
MetatypeImpl 元數(shù)據(jù)的反射
OpaqueImpl 不透明類型的反射
這里主要以Struct
的反射為例
- 首先查看
ReflectionMirrorImpl
的底層定義
// Abstract base class for reflection implementations.
struct ReflectionMirrorImpl {
const Metadata *type;
OpaqueValue *value;
// 顯示的樣式
virtual char displayStyle() = 0;
// 屬性個(gè)數(shù)
virtual intptr_t count() = 0;
// 獲取偏移值
virtual intptr_t childOffset(intptr_t index) = 0;
// 獲取元數(shù)據(jù)
virtual const FieldType childMetadata(intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *)) = 0;
//獲取屬性
virtual AnyReturn subscript(intptr_t index, const char **outName,
void (**outFreeFunc)(const char *)) = 0;
//獲取枚舉的case名字
virtual const char *enumCaseName() { return nullptr; }
#if SWIFT_OBJC_INTEROP
// 快速查找
virtual id quickLookObject() { return nil; }
#endif
// For class types, traverse through superclasses when providing field
// information. The base implementations call through to their local-only
// counterparts.
// 遞歸查找父類的屬性
virtual intptr_t recursiveCount() {
return count();
}
// 遞歸查找父類屬性的偏移值
virtual intptr_t recursiveChildOffset(intptr_t index) {
return childOffset(index);
}
// 遞歸獲取父類的元數(shù)據(jù)
virtual const FieldType recursiveChildMetadata(intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *))
{
return childMetadata(index, outName, outFreeFunc);
}
// 析構(gòu)函數(shù)
virtual ~ReflectionMirrorImpl() {}
};
- 進(jìn)入
StructImpl
結(jié)構(gòu)體的底層實(shí)現(xiàn),需要注意一下幾點(diǎn):
// Implementation for structs.
// ReflectionMirrorImpl 的子類 StructImpl 結(jié)構(gòu)體反射
struct StructImpl : ReflectionMirrorImpl {
bool isReflectable() {//是否支持反射
const auto *Struct = static_cast<const StructMetadata *>(type);
const auto &Description = Struct->getDescription();
return Description->isReflectable();
}
// 用 s 的顯式樣式來表明這是一個(gè)結(jié)構(gòu)體
char displayStyle() {
return 's';
}
intptr_t count() {
if (!isReflectable()) {
return 0;
}
// 首先也是找到metadata壶运,然后通過metadata找到desc耐齐,然后找到fields,即 NumFields 記錄屬性的count
auto *Struct = static_cast<const StructMetadata *>(type);
return Struct->getDescription()->NumFields;//屬性的count
}
intptr_t childOffset(intptr_t i) {
auto *Struct = static_cast<const StructMetadata *>(type);
// 邊界檢查
if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
// Load the offset from its respective vector.
// 獲取偏移值
return Struct->getFieldOffsets()[i];
}
const FieldType childMetadata(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
StringRef name;
FieldType fieldInfo;
//通過getFieldAt獲取屬性的名稱
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
*outName = name.data();
*outFreeFunc = nullptr;
return fieldInfo;
}
// subscript 用來獲取當(dāng)前屬性的名稱和值
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
// 獲取metaadata
auto fieldInfo = childMetadata(i, outName, outFreeFunc);
auto *bytes = reinterpret_cast<char*>(value);
// 獲取屬性的偏移值
auto fieldOffset = childOffset(i);
// 計(jì)算字段存儲(chǔ)的指針
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
return copyFieldContents(fieldData, fieldInfo);
}
};
1蒋情、
count
方法中屬性個(gè)數(shù)的獲取埠况,是通過metadata
,然后找到其desc棵癣,然后找到NumFields獲取的辕翰,即NumFields 記錄屬性的count
2、subscript
方法主要用來獲取當(dāng)前屬性的名稱和值
- 首先獲取
metadata
- 然后獲取屬性的偏移值
fieldOffset
- 通過首地址+偏移值狈谊,計(jì)算屬性存儲(chǔ)的指針
其他幾種的分析類似喜命,這里不再作說明
仿寫Mirror結(jié)構(gòu)
以上源碼說了這么多,是不是還是有點(diǎn)難以理解河劝,下面我們通過仿寫底層的結(jié)構(gòu)來幫助理解Mirror獲取屬性和值的原理
TargetStructMetadata結(jié)構(gòu)體:struct的反射類
-
從Struct的反射類
StructImpl
中可以知道壁榕,其type的類型是StructMetadata
在
Metadata.h
文件中搜索StructMetadata
,其真正的類型是TargetStructMetadata
using StructMetadata = TargetStructMetadata<InProcess>;
- 從
TargetStructMetadata -> TargetValueMetadata
結(jié)構(gòu)體丧裁,而
TargetValueMetadata
繼承自TargetMetadata
护桦,在Swift-進(jìn)階 02:類、對(duì)象煎娇、屬性文章中二庵,我們已經(jīng)知道贪染,TargetMetadata
中有一個(gè)屬性kind(相當(dāng)于OC中的isa),而TargetValueMetadata
除了擁有父類的kind催享,還有一個(gè)description
杭隙,用于記錄元數(shù)據(jù)的描述
/// The common structure of metadata for structs and enums.
template <typename Runtime>
struct TargetValueMetadata : public TargetMetadata<Runtime> {
using StoredPointer = typename Runtime::StoredPointer;
TargetValueMetadata(MetadataKind Kind,
const TargetTypeContextDescriptor<Runtime> *description)
: TargetMetadata<Runtime>(Kind), Description(description) {}
//用于記錄元數(shù)據(jù)的描述
/// An out-of-line description of the type.
TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
......
}
TargetValueTypeDescriptor類:記錄metadata信息
- 由上面可知,
Description
的類型是TargetValueTypeDescriptor
因妙,其中有兩個(gè)屬性-
NumFields
用于記錄屬性的count -
FieldOffsetVectorOffset
用于記錄屬性在metadata中便宜向量的偏移量
-
template <typename Runtime>
class TargetStructDescriptor final
: public TargetValueTypeDescriptor<Runtime>,
public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
TargetTypeGenericContextDescriptorHeader,
/*additional trailing objects*/
TargetForeignMetadataInitialization<Runtime>,
TargetSingletonMetadataInitialization<Runtime>> {
......
/// The number of stored properties in the struct.
/// If there is a field offset vector, this is its length.
uint32_t NumFields;//記錄屬性的count
/// The offset of the field offset vector for this struct's stored
/// properties in its metadata, if any. 0 means there is no field offset
/// vector.
uint32_t FieldOffsetVectorOffset;//記錄屬性在metadata中便宜向量的偏移量
......
}
- 進(jìn)入其繼承鏈
TargetValueTypeDescriptor -> TargetTypeContextDescriptor
類痰憎,其中有3個(gè)屬性-
Name
用于記錄類型的名稱,標(biāo)識(shí)當(dāng)前的類型 -
AccessFunctionPtr
指向此類型的metadata訪問函數(shù)的指針 -
Fields
指向類型的descriptor的指針
-
template <typename Runtime>
class TargetTypeContextDescriptor
: public TargetContextDescriptor<Runtime> {
public:
/// The name of the type. 類型的名稱
TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;
/// A pointer to the metadata access function for this type.
/// 指向此類型的元數(shù)據(jù)訪問函數(shù)的指針
/// The function type here is a stand-in. You should use getAccessFunction()
/// to wrap the function pointer in an accessor that uses the proper calling
/// convention for a given number of arguments.
TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
/*Nullable*/ true> AccessFunctionPtr;
/// A pointer to the field descriptor for the type, if any.指向類型的字段描述符的指針
TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
/*nullable*/ true> Fields;
......
}
- 進(jìn)入
TargetContextDescriptor
基類的定義攀涵,其中有兩個(gè)參數(shù)-
Flags
用于表示描述context的標(biāo)志铣耘,包含kind和version -
Parent
用于表示父類的context,如果是在頂層以故,則表示沒有父類蜗细,則為NULL
-
/// Base class for all context descriptors.
template<typename Runtime>
struct TargetContextDescriptor {
/// Flags describing the context, including its kind and format version.
ContextDescriptorFlags Flags;
/// The parent context, or null if this is a top-level context.
TargetRelativeContextPointer<Runtime> Parent;
......
}
從上述的分析中我們可以得知,
- 屬性的獲取時(shí)通過
baseDesc->Fields.get();
(在ReflectionMirror.mm
文件中getFieldAt
方法)怒详,即是通過Description
中的Fields
屬性獲取炉媒,所以還需要分析Fields
的類型TargetRelativeDirectPointer
,其內(nèi)部的類型是FieldDescriptor
RelativeDirectPointerImpl類:存放offset偏移量
-
TargetRelativeDirectPointer
的真正類型是RelativeDirectPointer -> RelativeDirectPointerImpl
,RelativeDirectPointerImpl
主要用于存放offset
偏移量-
屬性
RelativeOffset
昆烁,用于表示屬性的相對(duì)偏移值
吊骤,而不是直接存儲(chǔ)地址,如下所示 其中
PointerTy静尼、ValueTy
就是傳入的類型T白粉、T的指針類型
-
template<typename T, bool Nullable, typename Offset>
class RelativeDirectPointerImpl {
private:
/// The relative offset of the function's entry point from *this.
Offset RelativeOffset;
......
public:
using ValueTy = T;//是一個(gè)值
using PointerTy = T*;//是一個(gè)指針
}
//get方法 - 用于獲取屬性
PointerTy get() const & {
// Check for null.檢查是否為空
if (Nullable && RelativeOffset == 0)
return nullptr;
// The value is addressed relative to `this`. 值是相對(duì)于“this”尋址的
uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
return reinterpret_cast<PointerTy>(absolute);
}
......
}
??
<!--applyRelativeOffset的實(shí)現(xiàn)-->
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;
return base + extendOffset;//指針地址+存放的offset(偏移地址) -- 內(nèi)存平移獲取值
}
FieldDescriptor類:存放屬性
進(jìn)入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類:封裝屬性
進(jìn)入FieldRecord
類蜗元,其定義如下
class FieldRecord {
const FieldRecordFlags Flags;
public:
const RelativeDirectPointer<const char> MangledTypeName;
const RelativeDirectPointer<const char> FieldName;
上面主要分析了結(jié)構(gòu)體通過Mirror獲取屬性和值涉及的類和結(jié)構(gòu)體或渤,其結(jié)構(gòu)仿寫代碼如下
/// metadata元數(shù)據(jù)
struct StructMetadata {
// (取自類 - TargetMetadata:kind)
//(繼承關(guān)系:TargetStructMetadata -> TargetValueMetadata -> TargetMetadata)
var kind: Int
// (取自結(jié)構(gòu)體 - TargetValueMetadata:Description)
var desc: UnsafeMutablePointer<StructMetadataDesc>
}
/// metada的描述信息
struct StructMetadataDesc {
// (取自底層結(jié)構(gòu)體 - TargetContextDescriptor:flags + parent)
var flags: Int32
var parent: Int32
// (取自底層類 - TargetTypeContextDescriptor:name + AccessFunctionPtr + Fields)
//type的名稱
//相對(duì)指針位置的存儲(chǔ)
var name: RelativeDirectPointer<CChar>
//補(bǔ)充完整
var AccessFunctionPtr: RelativeDirectPointer<UnsafeRawPointer>
//是通過Fields的getFiledName獲取屬性名稱
var Fields: RelativeDirectPointer<FieldDescriptor>
// (取自底層類 - TargetClassDescriptor:NumFields + FieldOffsetVectorOffset)
//屬性的count
var NumFields: Int32
var FieldOffsetVectorOffset: Int32
}
/// 屬性的描述信息
//(取自底層類 - FieldDescriptor)
struct FieldDescriptor {
var MangledTypeName: RelativeDirectPointer<CChar>
var Superclass: RelativeDirectPointer<CChar>
var Kind: UInt16
var FieldRecordSize: Int16
var NumFields: Int32
//每個(gè)屬性都是FieldRecord系冗,記錄在這個(gè)結(jié)構(gòu)體中
var fields: FieldRecord//數(shù)組中是一個(gè)連續(xù)的存儲(chǔ)空間
}
/// 屬性封裝類
//(取自底層類 - FieldRecord)
struct FieldRecord{
var Flags: Int32
var MangledTypeName: RelativeDirectPointer<CChar>
var FieldName: RelativeDirectPointer<CChar>
}
/// 記錄offset偏移值
struct RelativeDirectPointer<T>{
var offset: Int32
//模擬RelativeDirectPointerImpl類中的get方法 this+offset指針
mutating func get() -> UnsafeMutablePointer<T>{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
/*
獲得self,變?yōu)閞aw薪鹦,然后+offset
- UnsafeRawPointer(p) 表示this
- advanced(by: numericCast(offset) 表示移動(dòng)的步長(zhǎng)掌敬,即offset
- assumingMemoryBound(to: T.self) 表示假定類型是T,即自己制定的類型
- UnsafeMutablePointer(mutating:) 表示返回的指針類型
*/
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))
}
}
}
其使用如下
- 定義一個(gè)CJLTeacher類
struct CJLTeacher {
var age = 18
var name = "CJL"
}
- 1池磁、首先獲取指向metadata的指針
- 2、然后獲取字符串的地址华临,例如name扶供,并讀取內(nèi)存值
/將t1綁定到StructMetadata(unsafeBitCast-按位強(qiáng)轉(zhuǎn)扳碍,非常危險(xiǎn)唧垦,沒有任何校驗(yàn)坊秸、沒有任何修飾)
//unsafeBitCast - 所有的內(nèi)存按位轉(zhuǎn)換
//1星瘾、先獲取指向metadata的指針
let ptr = unsafeBitCast(CJLTeacher.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)
//2念逞、然后獲取字符串的地址
/*
ptr.pointee 表示StructMetadata
ptr.pointee.desc.pointee 表示StructMetadataDesc
ptr.pointee.desc.pointee.name 表示RelativeDirectPointer<T>
*/
let namePtr = ptr.pointee.desc.pointee.name.get()
print(String(cString: namePtr))
//讀取內(nèi)存值
print(ptr.pointee.desc.pointee.NumFields)
- 3、獲取首地址仰剿,通過指針移動(dòng)來獲取訪問屬性的地址,例如輸出
age
屬性
//獲取首地址
let filedDescriptorPtr = ptr.pointee.desc.pointee.Fields.get()
//指針移動(dòng)來獲取訪問屬性的地址
let recordPtr = withUnsafePointer(to: &filedDescriptorPtr.pointee.fields) {
/*
- UnsafeRawPointer + assumingMemoryBound -- 類型指針
- advanced 類型指針只需要移動(dòng) 下標(biāo)即可
*/
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: FieldRecord.self).advanced(by: 0))
}
//輸出age屬性
print(String(cString: recordPtr.pointee.FieldName.get()))
如果將advanced
中的0改成1箱锐,輸出name
總結(jié)
所以綜上所述比勉,Mirror反射
干的事情:
1、Mirror在實(shí)例對(duì)象的
metadata
中找到Descriptor
-
2驹止、在
Descriptor
中- 找到
name
浩聋,獲取類型(相當(dāng)于type名稱) - 找到
numFields
,獲取屬性個(gè)數(shù)
- 找到
-
3臊恋、找到
FieldDescriptor
中的fields
衣洁,來找到對(duì)當(dāng)前屬性的描述,然后通過指針移動(dòng)抖仅,獲取其他屬性
以上就是整個(gè)mirror在底層做的事情坊夫,如下所示,以struct為例的一個(gè)流程
【補(bǔ)充】
swift中的
type(of:)
撤卢、dump(t)
就是基于Mirror的反射原理來實(shí)現(xiàn)的swift中JSON解析的三方庫
HandyJSON
其原理就是Mirror反射的原理环凿,本質(zhì)就是利用metadata元數(shù)據(jù)中的descriptor,然后通過字段的訪問放吩,做內(nèi)存的賦值(后續(xù)會(huì)完整分析HandyJSON)
所以智听,針對(duì)我們開頭的兩個(gè)問題,可以通過上面的Mirror反射的原理
來進(jìn)行解釋
1屎慢、系統(tǒng)是如何通過Mirror
獲取對(duì)應(yīng)的屬性以及值的瞭稼?
參考上述的Mirror原理總結(jié)
2、Swift眾所周知是一門靜態(tài)語言腻惠,系統(tǒng)在底層到底做了什么,使swift具有了反射的特性呢欲虚?
Swift 的反射機(jī)制
是基于一個(gè)叫 Mirror
的 struct 來實(shí)現(xiàn)的集灌。即為具體的 subject 創(chuàng)建一個(gè) Mirror,然后就可以通過它查詢這個(gè)對(duì)象subject。簡(jiǎn)單理解就是 Mirror通過meatadata
欣喧,在其內(nèi)部創(chuàng)建了一個(gè)結(jié)構(gòu)腌零,用于輸出metadata中的descriptor