前言:
上篇文章分析了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
不透明类型的反射