第六节课:Mirror源码解析
本篇主要分析Mirror的源码,底层实现方式,篇幅稍微多点,就单独写一篇文章啦
上一篇文章我们简单接触了下Mirror
,简单在JSON解析
中应用了一下,但是留下很多疑问:
- 系统是如何通过Mirror来取到对应Value的值的
- Swift是一门静态型的语言,底层中做了什么事情,才让Swift有个反射特性?
下面我们来对Mirror的底层进行探索
源码分析
这时候就得掏出我们的源码文件了,再里面搜索Mirror.Swift
路径为swift->stdlib->public->core->Mirror.swift
首先Mirror
是个结构体类型
初始化方法传入的Any
主要实现方法是分在两个文件里的
ReflectionMirror.swift
里面
ReflectionMirror.mm
里面
swift 使用C文件方法技巧
我们发现两者之间交互的方法并不是通过桥接文件等,而是通过@_silgen_name
修饰符
首先我们创建个C文件,并定义一个方法
//.h声明
int hzm_add(int a, int b);
//.c中实现
int hzm_add(int a, int b){
return a+b;
}
我们要想在Swift中使用,必须在桥接文件引入头文件
#import "test.h"
var value = hzm_add(10, 20)
print(value)
<打印结果>
30
可以将上述代码中的引用头文件去掉或者删除桥接文件,采用@_silgen_name
关键字
@_silgen_name("hzm_add")
func swift_hzm_add(_ a: Int32, _ b: Int32) -> Int32
var value = swift_hzm_add(20, 30)
print(value)
<打印结果>
50
继续分析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
}
}
public var superclassMirror: Mirror? {
return _makeSuperclassMirror()
}
nternal let _makeSuperclassMirror: () -> Mirror?
1、通过_getNormalizedType
获取传入的subject
的真正类型
2、通过_getChildCount
方法获取类中的属性个数
3、遍历属性,通过getChild
方法(C++的_getChild 函数的简单封装)将标签名字中包含的C字符串转换为Swift字符串,并将属性存储到字典中,赋值给Mirror的属性children
4、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, 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
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: {//可选
......
}
......
}
static std::tuple
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(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);
}
template<> const Metadata *
ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const {
// 根据 获取此存在类型使用的表示形式 判断
switch (getRepresentation()) {
case ExistentialTypeRepresentation::Class: {
auto classContainer =
reinterpret_cast(container);
void *obj = classContainer->Value;
return swift_getObjectType(reinterpret_cast(obj));
}
case ExistentialTypeRepresentation::Opaque: {
auto opaqueContainer =
reinterpret_cast(container);
return opaqueContainer->Type;
}
case ExistentialTypeRepresentation::Error: {
const SwiftError *errorBox
= *reinterpret_cast(container);
return errorBox->getType();
}
}
swift_runtime_unreachable(
"Unhandled ExistentialTypeRepresentation in switch.");
}
call
中主要是一个大型switch声明和一些额外的代码去处理特殊的情况,主要是会ReflectionMirrorImpl
的子类实例
去结束调用 f
,然后会调用这个实例上的方法去让真正的工作完成。
1、首先根据unwrapExistential
获取type类型,其依赖于metaData
元数据
2、判断传入的passedType
是否为空,如果不为空,则直接赋值给type
3、使用 ReflectionMirrorImpl
子类的实例去结束调用f
,然后会调用这个实例上的方法去真正的工作完成
swift-source源码调试_getNormalizedType方法
运行swift源码,在Call函数的第一行加断点
在源码终端依次输入下面代码
class HZMTeacher{var age = 18}
var t = HZMTeacher()
let mirror = Mirror(reflecting: t)
运行结果如下,会在call的调用处断住
- 其中
value
是Mirror
实例 -
type
是type(of:)
获取的类型 -
T
是自己传入的类型
最终返回impl->type
,他的结构是ReflectionMirrorImpl
ReflectionMirrorImpl 反射基类
首先查看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(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(type);
return Struct->getDescription()->NumFields;//属性的count
}
intptr_t childOffset(intptr_t i) {
auto *Struct = static_cast(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(value);
// 获取属性的偏移值
auto fieldOffset = childOffset(i);
// 计算字段存储的指针
auto *fieldData = reinterpret_cast(bytes + fieldOffset);
return copyFieldContents(fieldData, fieldInfo);
}
};
1、count
方法中属性个数的获取,是通过metadata
,然后找到其desc
,然后找到NumFields
获取的,即NumFields
记录属性的count
2、subscript
方法主要用来获取当前属性的名称和值
- 首先获取
metadata
- 然后获取属性的偏移值
fieldOffset
- 通过首地址+偏移值,计算属性存储的指针
仿写Mirror结构
从Struct的反射类StructImpl
中可以知道,其type的类型是StructMetadata
根据源码探索,以struct
类型为例,可知structMetaData
结构为
在Metadata.h
文件中搜索StructMetadata
,其真正的类型是TargetStructMetadata
using StructMetadata = TargetStructMetadata;
在之前的文章中我们已经了解过,TargetMetadata
中有一个属性kind
(相当于OC中的isa),而TargetValueMetadata
除了拥有父类的kind
,还有一个description
,用于记录元数据的描述
/// The common structure of metadata for structs and enums.
template
struct TargetValueMetadata : public TargetMetadata {
using StoredPointer = typename Runtime::StoredPointer;
TargetValueMetadata(MetadataKind Kind,
const TargetTypeContextDescriptor *description)
: TargetMetadata(Kind), Description(description) {}
//用于记录元数据的描述
/// An out-of-line description of the type.
TargetSignedPointer * __ptrauth_swift_type_descriptor> Description;
......
}
TargetValueTypeDescriptor类:记录metadata信息
Description
的类型是TargetValueTypeDescriptor
,其中有两个属性
-
NumFields
用于记录属性的count
-
FieldOffsetVectorOffset
用于记录属性在metadata
中便宜向量的偏移量
进入其继承链TargetValueTypeDescriptor
-> TargetTypeContextDescriptor
类,其中有3个属性
-
Name
用于记录类型的名称,标识当前的类型 -
AccessFunctionPtr
指向此类型的metadata访问函数的指针 -
Fields
指向类型的descriptor的指针
进入TargetContextDescriptor
基类的定义,其中有两个参数
-
Flags
用于表示描述context
的标志,包含kind
和version
-
Parent
用于表示父类的context
,如果是在顶层,则表示没有父类,则为NULL
从上述的分析中我们可以得知:
属性的获取时通过baseDesc->Fields.get()
;(在ReflectionMirror.mm
文件中getFieldAt
方法),即是通过Description
中的Fields
属性获取,所以还需要分析Fields
的类型TargetRelativeDirectPointer
,其内部的类型是FieldDescriptor
RelativeDirectPointerImpl类:存放offset偏移量
TargetRelativeDirectPointer
的真正类型是RelativeDirectPointer
-> RelativeDirectPointerImpl
,RelativeDirectPointerImpl
主要用于存放offset
偏移量
属性RelativeOffset
,用于表示属性的相对偏移值,而不是直接存储地址,如下所示
其中PointerTy、ValueTy
就是传入的类型T、T的指针类型
template
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(absolute);
}
......
}
template
static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
static_assert(std::is_integral::value &&
std::is_signed::value,
"offset type should be signed integer");
// 指针地址
auto base = reinterpret_cast(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(this + 1);
}
public:
const RelativeDirectPointer MangledTypeName;
const RelativeDirectPointer Superclass;
......
const FieldDescriptorKind Kind;
const uint16_t FieldRecordSize;
const uint32_t NumFields;
......
// 获取所有属性,每个属性用FieldRecord封装
llvm::ArrayRef getFields() const {
return {getFieldRecordBuffer(), NumFields};
}
......
}
FieldRecord类:封装属性
进入FieldRecord
类,其定义如下
class FieldRecord {
const FieldRecordFlags Flags;
public:
const RelativeDirectPointer MangledTypeName;
const RelativeDirectPointer FieldName;
上面主要分析了结构体通过Mirror获取属性和值涉及的类和结构体,其结构仿写代码如下
按照structMetadata
格式,尝试读取struct
的类型:
(get
:仿照源码中RelativeDirectPointer
(相对位置指针)进行偏移
,获取真实内存值
)
/// metadata元数据
struct StructMetadata {
// (取自类 - TargetMetadata:kind)
//(继承关系:TargetStructMetadata -> TargetValueMetadata -> TargetMetadata)
var kind: Int
// (取自结构体 - TargetValueMetadata:Description)
var description: UnsafeMutablePointer
}
/// metada的描述信息
struct StructMetadataDesc {
// (取自底层结构体 - TargetContextDescriptor:flags + parent)
var flags: UInt32
var parent: UInt32 ,
//(取自底层类 - TargetTypeContextDescriptor:name + AccessFunctionPtr + Fields)
//type的名称
//相对指针位置的存储
var name: RelativeDirectPointer
//补充完整
var AccessFunctionPtr: RelativeDirectPointer
//是通过Fields的getFiledName获取属性名称
var Fields: RelativeDirectPointer
// (取自底层类 - TargetClassDescriptor:NumFields + FieldOffsetVectorOffset)
//属性的count
var NumFields: Int32
var FieldOffsetVectorOffset: Int32
}
/// 属性的描述信息
//(取自底层类 - FieldDescriptor)
struct FieldDescriptor {
var MangledTypeName: RelativeDirectPointer
var Superclass: RelativeDirectPointer
var Kind: UInt16
var FieldRecordSize: Int16
var NumFields: Int32
//每个属性都是FieldRecord,记录在这个结构体中
var fields: FieldRecord//数组中是一个连续的存储空间
}
/// 属性封装类
//(取自底层类 - FieldRecord)
struct FieldRecord{
var Flags: Int32
var MangledTypeName: RelativeDirectPointer
var FieldName: RelativeDirectPointer
}
/// 记录offset偏移值
struct RelativeDirectPointer{
var offset: Int32
//模拟RelativeDirectPointerImpl类中的get方法 this+offset指针
mutating func get() -> UnsafeMutablePointer {
let offset = self.offset
// withUnsafePointer获取指针
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))
}
}
}
struct HZMStruct {
var age = 18
var name = "HZM"
}
//将t1绑定到StructMetadata(unsafeBitCast-按位强转,非常危险,没有任何校验、没有任何修饰)
//unsafeBitCast - 所有的内存按位转换
//1、先获取指向metadata的指针
let p = unsafeBitCast(HZMStruct.self as Any.Type, to: UnsafeMutablePointer.self)
//2、然后获取字符串的地址
/*
p.pointee 表示StructMetadata
p.pointee.desc.pointee 表示StructMetadataDesc
p.pointee.desc.pointee.name 表示RelativeDirectPointer
*/
let namePtr = p.pointee.description.pointee.name.get()
// name是CChar类型,转为字符串输出
print(String(cString: namePtr))
<打印结果>
HZMStuct
获取首地址,通过指针移动来获取访问属性的地址,例如输出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
属性
总结
1.Mirror
在实例对象的metadata
中找到Descriptor
2.在Descriptor
中
找到name
,获取类型(相当于type名称)
找到numFields
,获取属性个数
3.找到FieldDescriptor
中的fields
,来找到对当前属性的描述,然后通过指针移动,获取其他属性
PS:这篇文章其实早就写好了,但是由于我对这块的理解还是一直处于懵懂的状态,所以想着后面再多看几遍理解透彻再发,这一耽误过了好久,还是先发出来,慢慢消化吸收吧。前面的几篇文章其实更多的借鉴别人的(LGPerson月月课代表),自己理解上还是有一定遗漏,后面还是希望通过自己更加深入理解一下。