swfit进阶-11-swift中的Mirror的原理

语言: CN / TW / HK

「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」。

  • 之前我们了解了Mirror的使用方法,以及通过Mirror解析Json,转换为model。本文主要介绍下Mirror的原理

1. 源码分析

  • Mirror.swift文件中找到Mirror,是一个结构体类型

image.png

其初始化方法中,先判断传入的对象subject是否遵循CustomReflectable协议,如果符合的话则通过customMirror确定对象的属性。否则通过internalReflecting的方法进行初始化。 - internalReflecting查看

image.png 主要是:1.通过_getNormalizedType方法获取传入的subject的类型2.获取对象的属性个数,并遍历属性存储到字典中。3.设置获取父类的 Mirror,继承的关系因此Mirror有个superclassMirror的属性,会返回该类的父类。4.设置MiroordisplayStyle属性。5.设置 subjectType_defaultDescendantRepresentation属性。

  • 查看_getNormalizedType的实现

image.png 函数上面使用了一个编译字段 @_silgen_name,这个是 Swift 的一个隐藏符号,作⽤是将某个C/C++函数直接映射为 Swift 函数。也就是我们在调用 _getNormalizedType 函数的时候,最终会调用C++中的swift_reflectionMirror_normalizedType -> Call方法

image.png 我们看下call的实现

image.png 主要分为类的调用和非类的调用,对于非类的impl实现通过一个枚举进行判断ReflectionMirrorImpl,它通过 kind 来判断实例的类型,从而拿到不同类型对应的 impl,调用非类的 call(&impl)。而类是调用 callClass

ReflectionMirrorImpl的种类主要有以下几种: - TupleImpl 元组的反射 - StructImpl 结构体的反射 - EnumImpl 枚举的反射 - ClassImpl 类的反射 - MetatypeImpl 元数据的反射 - OpaqueImpl 不透明类型的反射

我们以StructImpl为例子查看

image.png 通过 isReflectable 函数来判断是否接受反射,它的实现无非就是拿到 Description,通过 DescriptionisReflectable 函数来判断的。在获取 count 的时候用到了 isReflectable 函数,代码如下:

image.png 如果不支持反射,直接返回 0,否则走到下面,调用了一个 getInfo 函数。查看getInfo 函数,它的实现如下:

image.png 我们查看getFieldAt的实现

image.png 这里拿到 Description,通过 Description 拿到 Fields,而 Fields 里面包含了属性信息,既然拿到了 Fields,就可以拿到属性相关的信息了。

2.小结

Mirror通过实例对象的meatadata,在其内部创建了一个结构,用于输出metadata中的descriptor,在descriptor中找到namenumFields,通过FieldDescriptor中的fields,来找到对当前属性的描述,然后通过指针移动,获取其他属性