本文主要是分析Mirror的底层实现,以及根据Mirror底层原理仿写其结构的实现
在Swift-进阶 06:反射Mirror & 错误处理文章中,我们介绍了Mirror的使用,即JSON解析,对此我们有如下一些疑问:
- 1、系统是如何通过
Mirror
获取对应的属性以及值的? - 2、Swift众所周知是一门静态语言,系统在底层到底做了什么,使swift具有了反射的特性呢?
下面我们来对Mirror的底层实现进行探索
Mirror底层源码分析
反射的API
主要是由两部分实现的
- 一部分是通过Swift实现,即
ReflectionMirror.swift
- 一部分是通过C++实现,即
ReflectionMirror.mm
- 两者之间是通过暴露给swift的C++函数进行通信,即
@_silgen_name
修饰符会通知swift编译器将这个swift函数映射成C++函数的符号 - Mirror的源码是在
Mirror.swift
文件中,路径为swift->stdlib->public->core->Mirror.swift
swift 使用技巧
使用@_silgen_name
关键字声明的方法,实际调用是括号中的方法,例如swift_cjl_add
实际调用的是c中的cjl_add
- 通过C定义一个方法,在swift中使用
<!--1、定义c方法--> //.h声明 int cjl_add(int a, int b); //.c中实现 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、打印结果--> 30
- 可以将上述代码中的第2步去掉删除,采用
@_silgen_name
关键字
<!--1、swift中针对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、打印结果--> 50
分析Mirror
- 在
Mirror.swift
文件中找到Mirror
,是一个结构体类型
- 查找其初始化方法
public init(reflecting subject: Any)
public init(reflecting subject: Any) { //判断 subject 是否符合 CustomReflectable动态类型 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值的类型,通常是值的运行时类型 - */ internal init(internalReflecting subject: Any, subjectType: Any.Type? = nil, customAncestor: Mirror? = nil) { //根据_getNormalizedType获取传入的subject的真正类型,其中type(of: subject)获取的动态类型 let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject)) // 获取属性大小 let childCount = _getChildCount(subject, type: subjectType) // 遍历,将属性存储到字典中 let children = (0 ..< childCount).lazy.map({ // getChild函数时C++的_getChild 函数的简单封装,将标签名字中包含的C字符串转换为Swift字符串 getChild(of: subject, type: subjectType, index: $0) }) // 赋值给Mirror的属性children self.children = Children(children) // 设置父类反射 self._makeSuperclassMirror = {//按需求构建父类的Mirror的闭包 // 获取传入对象的类 guard let subjectClass = subjectType as? AnyClass, // 获取父类 let superclass = _getSuperclass(subjectClass) else { return nil//非类的类型、没有父类的类的Mirror,会获取到nil } // 调用者可以用一个可作为父类的Mirror直接返回Mirror实例来指定自定义的祖先的表现 // 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 } } // 给相同值返回一个将 superclass作为 subjectType的新的Mirror return Mirror(internalReflecting: subject, subjectType: superclass, customAncestor: customAncestor) } // 获取并解析显示的样式,并设置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
方法获取类中的属性个数3、遍历属性,通过
getChild
方法(C++的_getChild
函数的简单封装)将标签名字中包含的C字符串转换为Swift字符串,并将属性存储到字典中,赋值给Mirror的属性children4、Mirror有一个属性
superclassMirror
,会返回该类的父类,其底层是返回一个_makeSuperclassMirror
属性,用于保存父类的Mirror闭包。首先会通过subjectType
获取父类,然后按照需求构建父类的Mirror闭包,如果是非类的类型、没有父类的类
的Mirror,会获取到nil
。反之,则直接返回一个可作为父类的Mirror的实例对象。5、获取并解析显示的样式,并设置Mirror的其他属性
- 进入
_getNormalizedType
的实现,根据定义,最终会调用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 实际需要传入的swift的值的指针 - T 该值的静态类型 - passedType 被显式传入且会用在反射过程中的类型 - f 传递被查找到的会被调用的实现的对象引用 - 返回值:返回f参数调用时的返回值 */ 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 子类的实例去结束调用f,然后会调用这个实例上的方法去真正的工作完成 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: {//结构体 ...... } case MetadataKind::Enum://枚举 case MetadataKind::Optional: {//可选 ...... } ...... } 👇 <!--unwrapExistential实现--> 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.如果该值是一个存在的容器,请查看它以反映包含的值。 // 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的实现--> template<> const Metadata * ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const { // 根据 获取此存在类型使用的表示形式 判断 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
中主要是一个大型switch
声明和一些额外的代码去处理特殊的情况,主要是会ReflectionMirrorImpl
的子类实例
去结束调用 f
,然后会调用这个实例上的方法去让真正的工作完成。
1、首先根据
unwrapExistential
获取type类型,其依赖于metaData
元数据2、判断传入的
passedType
是否为空,如果不为空,则直接赋值给type3、使用
ReflectionMirrorImpl
子类的实例去结束调用f
,然后会调用这个实例上的方法去真正的工作完成
swift-source源码调试_getNormalizedType方法
- 运行swift源码,在
Call
函数的第一行加断点 - 在源码终端依次输入下面代码
class CJLTeacher{var age = 18} var t = CJLTeacher() let mirror = Mirror(reflecting: t)
运行结果如下,会在call的调用处断住
中参数的调试结果如下:
- 其中
value
是Mirror
实例 type
是type(of:)
获取的类型T
是自己传入的类型
ReflectionMirrorImpl 反射基类
ReflectionMirrorImpl
的种类主要有以下几种:
- TupleImpl 元组的反射
- StructImpl 结构体的反射
- EnumImpl 枚举的反射
- ClassImpl 类的反射
- MetatypeImpl 元数据的反射
- OpaqueImpl 不透明类型的反射
这里主要以Struct
的反射为例
- 首先查看
ReflectionMirrorImpl
的底层定义
// Abstract base class for reflection implementations. struct ReflectionMirrorImpl { const Metadata *type; OpaqueValue *value; // 显示的样式 virtual char displayStyle() = 0; // 属性个数 virtual intptr_t count() = 0; // 获取偏移值 virtual intptr_t childOffset(intptr_t index) = 0; // 获取元数据 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); } // 递归获取父类的元数据 virtual const FieldType recursiveChildMetadata(intptr_t index, const char **outName, void (**outFreeFunc)(const char *)) { return childMetadata(index, outName, outFreeFunc); } // 析构函数 virtual ~ReflectionMirrorImpl() {} };
- 进入
StructImpl
结构体的底层实现,需要注意一下几点:
// Implementation for structs. // ReflectionMirrorImpl 的子类 StructImpl 结构体反射 struct StructImpl : ReflectionMirrorImpl { bool isReflectable() {//是否支持反射 const auto *Struct = static_cast<const StructMetadata *>(type); const auto &Description = Struct->getDescription(); return Description->isReflectable(); } // 用 s 的显式样式来表明这是一个结构体 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 用来获取当前属性的名称和值 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); // 计算字段存储的指针 auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset); return copyFieldContents(fieldData, fieldInfo); } };
1、
count
方法中属性个数的获取,是通过metadata
,然后找到其desc,然后找到NumFields获取的,即NumFields 记录属性的count
2、
subscript
方法主要用来获取当前属性的名称和值
- 首先获取
metadata
- 然后获取属性的偏移值
fieldOffset
- 通过首地址+偏移值,计算属性存储的指针
其他几种的分析类似,这里不再作说明
仿写Mirror结构
以上源码说了这么多,是不是还是有点难以理解,下面我们通过仿写底层的结构来帮助理解Mirror获取属性和值的原理
TargetStructMetadata结构体:struct的反射类
- 从Struct的反射类
StructImpl
中可以知道,其type的类型是StructMetadata
- 在
Metadata.h
文件中搜索StructMetadata
,其真正的类型是TargetStructMetadata
using StructMetadata = TargetStructMetadata<InProcess>;
从TargetStructMetadata -> TargetValueMetadata
结构体,而
TargetValueMetadata
继承自TargetMetadata
,在Swift-进阶 02:类、对象、属性文章中,我们已经知道,TargetMetadata
中有一个属性kind(相当于OC中的isa),而TargetValueMetadata
除了拥有父类的kind,还有一个description
,用于记录元数据的描述
/// 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) {} //用于记录元数据的描述 /// An out-of-line description of the type. TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description; ...... }
TargetValueTypeDescriptor类:记录metadata信息
- 由上面可知,
Description
的类型是TargetValueTypeDescriptor
,其中有两个属性
NumFields
用于记录属性的countFieldOffsetVectorOffset
用于记录属性在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中便宜向量的偏移量 ...... }
进入其继承链TargetValueTypeDescriptor -> TargetTypeContextDescriptor
类,其中有3个属性
Name
用于记录类型的名称,标识当前的类型AccessFunctionPtr
指向此类型的metadata访问函数的指针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. /// 指向此类型的元数据访问函数的指针 /// 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; ...... }
进入TargetContextDescriptor
基类的定义,其中有两个参数
Flags
用于表示描述context的标志,包含kind和versionParent
用于表示父类的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; ...... }
从上述的分析中我们可以得知,
- 属性的获取时通过
baseDesc->Fields.get();
(在ReflectionMirror.mm
文件中getFieldAt
方法),即是通过Description
中的Fields
属性获取,所以还需要分析Fields
的类型TargetRelativeDirectPointer
,其内部的类型是FieldDescriptor
RelativeDirectPointerImpl类:存放offset偏移量
TargetRelativeDirectPointer
的真正类型是RelativeDirectPointer -> RelativeDirectPointerImpl
,RelativeDirectPointerImpl
主要用于存放offset
偏移量
- 属性
RelativeOffset
,用于表示属性的相对偏移值
,而不是直接存储地址,如下所示
- 其中
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;//是一个值 using PointerTy = T*;//是一个指针 } //get方法 - 用于获取属性 PointerTy get() const & { // Check for null.检查是否为空 if (Nullable && RelativeOffset == 0) return nullptr; // The value is addressed relative to `this`. 值是相对于“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; return base + extendOffset;//指针地址+存放的offset(偏移地址) -- 内存平移获取值 }
FieldDescriptor类:存放属性
进入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; ...... // 获取所有属性,每个属性用FieldRecord封装 llvm::ArrayRef<FieldRecord> getFields() const { return {getFieldRecordBuffer(), NumFields}; } ...... }
FieldRecord类:封装属性
进入FieldRecord
类,其定义如下
class FieldRecord { const FieldRecordFlags Flags; public: const RelativeDirectPointer<const char> MangledTypeName; const RelativeDirectPointer<const char> FieldName;
上面主要分析了结构体通过Mirror获取属性和值涉及的类和结构体,其结构仿写代码如下
/// metadata元数据 struct StructMetadata { // (取自类 - TargetMetadata:kind) //(继承关系:TargetStructMetadata -> TargetValueMetadata -> TargetMetadata) var kind: Int // (取自结构体 - TargetValueMetadata:Description) var desc: UnsafeMutablePointer<StructMetadataDesc> } /// metada的描述信息 struct StructMetadataDesc { // (取自底层结构体 - TargetContextDescriptor:flags + parent) var flags: Int32 var parent: Int32 // (取自底层类 - TargetTypeContextDescriptor:name + AccessFunctionPtr + Fields) //type的名称 //相对指针位置的存储 var name: RelativeDirectPointer<CChar> //补充完整 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 //每个属性都是FieldRecord,记录在这个结构体中 var fields: FieldRecord//数组中是一个连续的存储空间 } /// 属性封装类 //(取自底层类 - 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,变为raw,然后+offset - UnsafeRawPointer(p) 表示this - advanced(by: numericCast(offset) 表示移动的步长,即offset - assumingMemoryBound(to: T.self) 表示假定类型是T,即自己制定的类型 - UnsafeMutablePointer(mutating:) 表示返回的指针类型 */ return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self)) } } }
其使用如下
- 定义一个CJLTeacher类
struct CJLTeacher { var age = 18 var name = "CJL" }
- 1、首先获取指向metadata的指针
- 2、然后获取字符串的地址,例如name,并读取内存值
/将t1绑定到StructMetadata(unsafeBitCast-按位强转,非常危险,没有任何校验、没有任何修饰) //unsafeBitCast - 所有的内存按位转换 //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)) //读取内存值 print(ptr.pointee.desc.pointee.NumFields)
- 3、获取首地址,通过指针移动来获取访问属性的地址,例如输出
age
属性
//获取首地址 let filedDescriptorPtr = ptr.pointee.desc.pointee.Fields.get() //指针移动来获取访问属性的地址 let recordPtr = withUnsafePointer(to: &filedDescriptorPtr.pointee.fields) { /* - UnsafeRawPointer + assumingMemoryBound -- 类型指针 - advanced 类型指针只需要移动 下标即可 */ return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: FieldRecord.self).advanced(by: 0)) } //输出age属性 print(String(cString: recordPtr.pointee.FieldName.get()))
如果将advanced
中的0改成1,输出name
总结
所以综上所述,Mirror反射
干的事情:
- 1、Mirror在实例对象的
metadata
中找到Descriptor
- 2、在
Descriptor
中
- 找到
name
,获取类型(相当于type名称) - 找到
numFields
,获取属性个数
- 3、找到
FieldDescriptor
中的fields
,来找到对当前属性的描述,然后通过指针移动,获取其他属性
以上就是整个mirror在底层做的事情,如下所示,以struct为例的一个流程
【补充】
- swift中的
type(of:)
、dump(t)
就是基于Mirror的反射原理来实现的 - swift中JSON解析的三方库
HandyJSON
其原理就是Mirror反射的原理,本质就是利用metadata元数据中的descriptor,然后通过字段的访问,做内存的赋值(后续会完整分析HandyJSON)
所以,针对我们开头的两个问题,可以通过上面的Mirror反射的原理
来进行解释
1、系统是如何通过Mirror
获取对应的属性以及值的?
参考上述的Mirror原理总结
2、Swift众所周知是一门静态语言,系统在底层到底做了什么,使swift具有了反射的特性呢?
Swift 的反射机制
是基于一个叫 Mirror
的 struct 来实现的。即为具体的 subject 创建一个 Mirror,然后就可以通过它查询这个对象subject。简单理解就是 Mirror通过meatadata
,在其内部创建了一个结构,用于输出metadata中的descriptor