Swift07-Mirror反射

864 阅读3分钟

Swift 进阶之路 文章汇总

前言:

上篇文章分析了Swift的方法调度,对于纯的Swift而言,没有动态特性。⽅法和属性不加任何修饰符的情况下不具备我们所谓的 Runtime 特性了,他的⽅法调度使用V-Table进行调度。那么除了@objcdynamic修饰的方法为Swift调用OCAPI提供了动态性以外,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**

  1. 通过_getNormalizedType获取传入的subject实例的真正类型

  2. 通过_getChildCount方法获取类中的属性个数

  3. 遍历属性,通过getChild方法(C++的_getChild 函数的简单封装)将标签名字中包含的C字符串转换为Swift字符串,并将属性存储到字典中,赋值给Mirror的属性children

  4. Mirror有一个属性superclassMirror,会返回该类的父类,其底层是返回一个_makeSuperclassMirror属性用于保存父类的Mirror

  5. 首先会通过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对应的字段(即属性),其中,类Classmetadata类型就是ClassMetadata

总结:

ReflectionMirrorImpl的子类除了StructImpl结构体的反射以外,还提供了以下几种反射:

  1. TupleImpl 元组的反射

  2. EnumImpl 枚举的反射

  3. MetatypeImpl 元数据的反射

  4. OpaqueImpl 不透明类型的反射