前言:
上篇文章分析了Swift的方法调度,对于纯的Swift而言,没有动态特性。⽅法和属性不加任何修饰符的情况下不具备我们所谓的 Runtime 特性了,他的⽅法调度使用V-Table进行调度。那么除了@objc和dynamic修饰的方法为Swift调用OC的API提供了动态性以外,Swift已另一种类似的方式,那就是本章所探索的Mirror反射机制
Mirror反射
定义:
**反射:**是指可以动态获取类型、成员信息,在运行时可以调用方法、属性等行为的特性.对于一个纯swift类来说,并不支持直接像OC runtime那样的操作,但是swift标准库依旧提供了反射机制,用来访问成员信息,即Mirror
简单使用:
由上图分析,Mirror在使用的过程中reflecting参数所传的应该是实例变量.
源码分析:
- 查看Mirror定义
根据上图所示,Mirror是一个结构体,其含义是为实例对象创建镜像,如果自定义镜像,需要遵守CustomReflectable协议
- 初始化源码分析:
打开**VSCode**的**Swift源码**,全局搜索**Mirror.swift**文件,查看**init**方法
全局搜索**internalReflecting**方法(路径为**swift->stdlib->public->core->ReflectionMirror.swift**)
-
通过
_getNormalizedType获取传入的subject实例的真正类型 -
通过
_getChildCount方法获取类中的属性个数 -
遍历属性,通过
getChild方法(C++的_getChild函数的简单封装)将标签名字中包含的C字符串转换为Swift字符串,并将属性存储到字典中,赋值给Mirror的属性children -
Mirror有一个属性
superclassMirror,会返回该类的父类,其底层是返回一个_makeSuperclassMirror属性用于保存父类的Mirror。 -
首先会通过
subjectType获取父类,然后按照需求构建父类的Mirror闭包,如果是非类的类型、没有父类的类的Mirror,会获取到nil。反之,则直接返回一个可作为父类的Mirror的实例对象
**
- 进入
**_getNormalizedType**的实现
**
在ReflectionMirror.mm文件中搜索call方法
查询unwrapExistential函数
在call函数中根据Kind来动态地对元组、结构体、枚举、类等类型调用相应的call闭包,call闭包有一个参数是ReflectionMirrorImpl *类型,元组、结构体、枚举、类都的实现都继承了它,在call闭包由f参数结束调用,把值返回到Mirror的初始化方法中,然后完成初始化工作
ReflectionMirrorImpl抽象基类
结构体的反射
- 结构体反射实现
- copyFieldContents
- AnyReturn
- getFieldAt取出名字和字段信息
ClassImpl 类的反射
下面的和StructImpl结构体一致查找getFieldAt函数,类ClassImpl与其它数据结构的不同在于,需要考虑继承链关系,于是多出了父类递归处理的一些函数。其实仔细看类ClassImpl反射子类中对属性的操作处理,都是先找到metadata,然后找到其description,再根据偏移值fieldOffset,就可得到真正索引i对应的字段(即属性),其中,类Class的metadata类型就是ClassMetadata
总结:
ReflectionMirrorImpl的子类除了StructImpl结构体的反射以外,还提供了以下几种反射:
-
TupleImpl元组的反射 -
EnumImpl枚举的反射 -
MetatypeImpl元数据的反射 -
OpaqueImpl不透明类型的反射