1. Mirror 简介

MirrorSwift中的反射机制的完结,它的本质是一个结构体。其部分源码(Swift 5.3.1)如下:

**

public struct Mirror {
  /// A suggestion of how a mirror's subject is to be interpreted.
  ///
  /// Playgrounds and the debugger will show a representation similar
  /// to the one used for instances of the kind indicated by the
  /// `DisplayStyle` case name when the mirror is used for display.
  public enum DisplayStyle {
    case `struct`, `class`, `enum`, tuple, optional, collection
    case dictionary, `set`
  }
    /// The static type of the subject being reflected.
    ///
    /// This type may differ from the subject's dynamic type when this mirror
    /// is the `superclassMirror` of another mirror.
    public let subjectType: Any.Type
    /// A collection of `Child` elements describing the structure of the
    /// reflected subject.
    public let children: Children
    /// A suggested display style for the reflected subject.
    public let displayStyle: DisplayStyle?
    /// A mirror of the subject's superclass, if one exists.
    public var superclassMirror: Mirror? {
      return _makeSuperclassMirror()
    }
}
  • subjectType:标明类型,被反射主体的类型
  • children:子元素集合
  • displayStyle:显现类型,根本类型为nil 枚举值: struct, class, enum, tuple, optional, collection, dictionary, set
  • superclassMirror:父类反射, 没有父类为nil

除了这些特点还有一些初始化办法,咱们最常用的便是初始化办法便是:

**

  /// Creates a mirror that reflects on the given instance.
  ///
  /// If the dynamic type of `subject` conforms to `CustomReflectable`, the
  /// resulting mirror is determined by its `customMirror` property.
  /// Otherwise, the result is generated by the language.
  ///
  /// If the dynamic type of `subject` has value semantics, subsequent
  /// mutations of `subject` will not observable in `Mirror`.  In general,
  /// though, the observability of mutations is unspecified.
  ///
  /// - Parameter subject: The instance for which to create a mirror.
  public init(reflecting subject: Any) {
    if case let customized as CustomReflectable = subject {
      self = customized.customMirror
    } else {
      self = Mirror(internalReflecting: subject)
    }
  }

依据源码咱们还能够看到能够运用customMirror,这个没太研究,在源码中能够看到许多CustomMirror的身影,感兴趣的能够去研究研究。关于非customMirror的统一运用Mirror(internalReflecting:)进行初始化。

关于customMirror的补充,摘抄自swiftGG Mirror 的作业原理

Mirror 答应类型用遵循 CustomReflectable 协议的办法供给一个自界说的标明办法。这给那些想标明得比内建方式更友好的类型供给一种有用的办法。 比方 Array 类型恪守 CustomReflectable 协议而且露出其间的元素为无标签的 ChildrenDictionary 运用这种办法露出其间的键值对为带标签的 Children

2. Mirror的简略运用

2.1 根本运用

这儿咱们经过运用Mirror打印目标的特点称号和特点值。

**

class Person {
    var name: String = "xiaohei"
    var age: Int = 18
    var height = 1.85
}
var p = Person()
var mirror = Mirror(reflecting: p.self)
print("目标类型:(mirror.subjectType)")
print("目标特点个数:(mirror.children.count)")
print("目标的特点及特点值")
for child in mirror.children {
    print("(child.label!)---(child.value)")
}

打印成果:

Swift-反射Mirror

咱们能够看到,特点称号和值都现已正常打印。

2.2 将目标转化为字典

首要咱们来体验一下将目标转化为字典。

class Animal {
    var name: String?
    var color: String?
    private var birthday: Date = Date(timeIntervalSince1970: 0)
}
class Cat: Animal {
    var master = "小黑"
    var like: [String] = ["mouse", "fish"]
    override init() {
        super.init()
        color = "黄色"
    }
}
func mapDic(mirror: Mirror) -> [String: Any] {
    var dic: [String: Any] = [:]
    for child in mirror.children {
        // 假如没有labe就会被扔掉
        if let label = child.label {
            let propertyMirror = Mirror(reflecting: child.value)
            print(propertyMirror)
            dic[label] = child.value
        }
    }
    // 增加父类特点
    if let superMirror = mirror.superclassMirror {
        let superDic = mapDic(mirror: superMirror)
        for p in superDic {
            dic[p.key] = p.value
        }
    }
    return dic
}
// Mirror运用
let cat = Cat()
cat.name = "大橘为重"
let mirror = Mirror(reflecting: cat)
let mirrorDic = mapDic(mirror: mirror)
print(mirrorDic)

打印成果:

Swift-反射Mirror

经过打印成果咱们能够看到,关于一些根本类型,现已可选类型的数据都现已转化为字典值,关于私有特点也能够完结转化。假如里边包括类则还需求进行递归处理。

2.3 转 JSON

注: 这儿并没有实在的转化成json字符串,仍是只转化成了字典,重要在思维,假如需求转化成json还需求许多优化,以及特殊字符串的考量。

其实说到反射咱们想到最多的应该便是JSON了,这儿咱们运用Mirror的特性,将目标转化成字典,对根本类型和类做了相应的处理,体会一下转json的思路。

首要咱们界说一个Person目标,代码如下:

struct Person {
    var name: String = "xiaohei"
    var age: Int = 18
    var isMale: Bool = true
    var address: Address? = Address(street: "xizhimen North")
    var height = 1.85
    var like: Array = ["eat", "sleep", "play"]
    var weight: Float = 75.0
    var some: Int?
}
struct Address {
    var street: String
}
// 创立一个Person目标
let p = Person()

为了通用性,咱们能够编写一个协议,用来为一切类型供给转化的办法,只需求恪守该协议就能够运用协议中的办法。

//能够转化为 Json 的协议
protocol CustomJSONProtocol {
    func toJSON() throws -> Any?
}

协议的完结过程中会有些过错,咱们也简略的界说个枚举,便利处理。为了更加详细的描绘过错信息,咱们增加了过错描绘和过错code。

// 转 json 时的过错类型
enum JSONMapError: Error{
    case emptyKey
    case notConformProtocol
}
// 过错描绘
extension JSONMapError: LocalizedError{
    var errorDescription: String?{
        switch self {
        case .emptyKey:
            return "key 为空"
        case .notConformProtocol:
           return "没恪守协议"
        }
    }
}
// errorcode
extension JSONMapError: CustomNSError{
    var errorCode: Int{
        switch self {
        case .emptyKey:
            return 100
        case .notConformProtocol:
            return 101
        }
    }
}

协议完结的代码:

extension CustomJSONProtocol {
    func toJSON() throws -> Any? {
        //创立 Mirror 类型
        let mirror = Mirror(reflecting: self)
        // 假如没有特点,比方一般类型String、Int等,直接回来自己
        guard !mirror.children.isEmpty else { return self }
        var result: [String:Any] = [:]
        // 遍历
        for children in mirror.children {
            if let value = children.value as? CustomJSONProtocol{
                if let key = children.label {
                    print(key)
                    result[key] = try value.toJSON()
                } else {
                   throw JSONMapError.emptyKey
                }
            } else {
                  throw JSONMapError.notConformProtocol
            }
        }
        return result
    }
}

将用到的类型都恪守协议

//将一般类型都遵照 CustomJSONProtocol 协议
extension Person: CustomJSONProtocol {}
extension String: CustomJSONProtocol {}
extension Int: CustomJSONProtocol {}
extension Bool: CustomJSONProtocol {}
extension Double: CustomJSONProtocol {}
extension Float: CustomJSONProtocol {}
extension Address: CustomJSONProtocol {}
// 数组需求独自处理,要不然就会报错emptyKey
extension Array: CustomJSONProtocol {
    func toJSON() throws -> Any? {
        return self
    }
}
//Optionai 需求特别对待,原因是假如直接回来,则会是 .Some: [...]
extension Optional: CustomJSONProtocol {
    func toJSON() throws -> Any? {
        if let x = self {
            if let value = x as? CustomJSONProtocol {
                return try value.toJSON()
            }
            throw JSONMapError.notConformProtocol
        }
        return nil
    }
}

终究咱们打印一下:

do {
    print(try p.toJSON()!)
} catch {
    print(error.localizedDescription)
    print((error as? JSONMapError)?.errorCode)
}

打印成果:

Swift-反射Mirror

咱们看到,关于some这空值,并没有存储到字典中,由于swift中的字典关于空值是删除的意思。

假如想将其转化成json还需修改”[]”为”{}”,这个关于数组和目标还欠好区别,另外关于json字符串内的一些value也有可能是应一串json还需求增加转义字符等。

所以总的来说,思路是这样的,要想实在的做成通用的转json的方案还需求许多的优化,比方说,咱们不可能将一切的根本类型都去恪守一个协议,这时分咱们也能够考虑运用泛型去作为办法的参数。

3. Mirror 源码解析

源码版本Swift 5.3.1

在本章节咱们将剖析Mirror的部分源码,查看其底层完结,终究经过Swift代码运用内存重绑定的方式,仿写一下Mirror,来更好的探究Mirror的原理,了解Mirror的思维。

咱们知道Swift是一门静态语言,那么在底层是怎样完结的获取对应的特点值的呢?又或者说Swift的反射特性是怎样完结的呢?下面咱们经过对Mirror底层源码的探究来寻找答案。

3.1 代码结构

Mirror的完结是由一部分Swift代码加上另一部分C++代码。Swift代码完结在ReflectionMirror.swift文件中,C++代码完结在ReflectionMirror.mm文件中。Swift更适合用在完结更Swift的接口,可是在Swift中不能直接拜访C++的类。这儿运用了@_silgen_name来完结Swift调用C++中的办法。举个比如:

**

@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount<T>(_: T, type: Any.Type) -> Int

@_silgen_name润饰符会通知Swift编译器将这个函数映射成swift_reflectionMirror_count符号,而不是Swift通常对应到的_getChildCount办法名润饰。需求留意的是,最前面的下划线标明这个润饰是被保留在规范库中的。在C++这边,这个函数是这样的。

// func _getChildCount<T>(_: T, type: Any.Type) -> Int
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
intptr_t swift_reflectionMirror_count(OpaqueValue *value,
                                      const Metadata *type,
                                      const Metadata *T) {
  return call(value, T, type, [](ReflectionMirrorImpl *impl) {
    return impl->count();
  });
}

SWIFT_CC(swift)会告知编译器这个函数运用的是Swift的调用约好,而不是C/C++的,SWIFT_RUNTIME_STDLIB_API标记这个函数,在Swift侧的一部分接口中,而且它还有标记为extern "C"的作用,然后避免C++的办法名润饰,并确保它在Swift侧会有预期的符号。一起C++的参数会去特意匹配在Swift中声明的函数调用。当Swift调用_getChildCount时,C++会用包括Swift值指针的value,包括类型参数type,包括类型呼应的泛型<T>T的函数参数来调用此函数。

简略的说便是运用@_silgen_name("xxx")润饰符润饰的Swift办法会调用括号中的xxx的符号,不管是C++的仍是C的都能够。

Mirror的在SwiftC++之间的悉数接口由以下函数组成:

@_silgen_name("swift_isClassType")
internal func _isClassType(_: Any.Type) -> Bool
@_silgen_name("swift_getMetadataKind")
internal func _metadataKind(_: Any.Type) -> UInt
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount<T>(_: T, type: Any.Type) -> Int
@_silgen_name("swift_reflectionMirror_recursiveCount")
internal func _getRecursiveChildCount(_: Any.Type) -> Int
@_silgen_name("swift_reflectionMirror_recursiveChildMetadata")
internal func _getChildMetadata(
  _: Any.Type,
  index: Int,
  outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
  outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any.Type
@_silgen_name("swift_reflectionMirror_recursiveChildOffset")
internal func _getChildOffset(
  _: Any.Type,
  index: Int
) -> Int
internal typealias NameFreeFunc = @convention(c) (UnsafePointer<CChar>?) -> Void
@_silgen_name("swift_reflectionMirror_subscript")
internal func _getChild<T>(
  of: T,
  type: Any.Type,
  index: Int,
  outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
  outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any
// Returns 'c' (class), 'e' (enum), 's' (struct), 't' (tuple), or '\0' (none)
@_silgen_name("swift_reflectionMirror_displayStyle")
internal func _getDisplayStyle<T>(_: T) -> CChar
internal func getChild<T>(of value: T, type: Any.Type, index: Int) -> (label: String?, value: Any) {
  var nameC: UnsafePointer<CChar>? = nil
  var freeFunc: NameFreeFunc? = nil
  let value = _getChild(of: value, type: type, index: index, outName: &nameC, outFreeFunc: &freeFunc)
  let name = nameC.flatMap({ String(validatingUTF8: $0) })
  freeFunc?(nameC)
  return (name, value)
}
#if _runtime(_ObjC)
@_silgen_name("swift_reflectionMirror_quickLookObject")
internal func _getQuickLookObject<T>(_: T) -> AnyObject?
@_silgen_name("_swift_stdlib_NSObject_isKindOfClass")
internal func _isImpl(_ object: AnyObject, kindOf: UnsafePointer<CChar>) -> Bool

3.2 初始化

在一开始咱们简略的介绍了Mirror的部分源码,也由此知道Mirror(reflecting:)初始化办法能够接受任意值,回来一个供给该值子元素集合Children的相关信息的实例。

经过Mirror(reflecting:)源码咱们能够知道,其底层调用的是internalReflecting办法。在ReflectionMirror.swift文件的extension Mirror中咱们能够找到该办法。其源码如下:

3.2.1 internalReflecting

 internal init(internalReflecting subject: Any,
              subjectType: Any.Type? = nil,
              customAncestor: Mirror? = nil)
  {
    let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
    let childCount = _getChildCount(subject, type: subjectType)
    let children = (0 ..< childCount).lazy.map({
      getChild(of: subject, type: subjectType, index: $0)
    })
    self.children = Children(children)
    self._makeSuperclassMirror = {
      guard let subjectClass = subjectType as? AnyClass,
            let superclass = _getSuperclass(subjectClass) else {
        return nil
      }
      // 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
        }
      }
      return Mirror(internalReflecting: subject,
                    subjectType: superclass,
                    customAncestor: customAncestor)
    }
    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
  }

源码剖析:

  • 首要是获取subjectType,假如传入的有值就运用传入的值,不然就经过_getNormalizedType函数去获取
  • 接下来便是经过_getChildCount获取childCount
  • 接下来是children,留意这儿是懒加载的
  • 紧接着是SuperclassMirror,这儿运用的是一个闭包的方式
  • 终究会获取并解析显现的样式,并设置Mirror剩下的特点。

3.2.2 _getNormalizedType

下面咱们就来看看_getNormalizedType函数内部的完结。依据上面的剖析咱们知道实践调用是swift_reflectionMirror_normalizedType。在ReflectionMirror.mm文件中咱们能够看到其源码:

// func _getNormalizedType<T>(_: 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; });
}

3.2.3 call函数

咱们能够看到这儿调用了一个call函数,终究回来的是impltype。首要咱们看看这call函数:

template<typename F>
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
          const F &f) -> decltype(f(nullptr))
{
  const Metadata *type;
  OpaqueValue *value;
  std::tie(type, value) = unwrapExistential(T, passedValue);
  if (passedType != nullptr) {
    type = passedType;
  }
  auto call = [&](ReflectionMirrorImpl *impl) {
    impl->type = type;
    impl->value = value;
    auto result = f(impl);
    return result;
  };
  auto callClass = [&] {
    if (passedType == nullptr) {
      // Get the runtime type of the object.
      const void *obj = *reinterpret_cast<const void * const *>(value);
      auto isa = _swift_getClass(obj);
      // Look through artificial subclasses.
      while (isa->isTypeMetadata() && isa->isArtificialSubclass()) {
        isa = isa->Superclass;
      }
      passedType = isa;
    }
  #if SWIFT_OBJC_INTEROP
    // If this is a pure ObjC class, reflect it using ObjC's runtime facilities.
    // ForeignClass (e.g. CF classes) manifests as a NULL class object.
    auto *classObject = passedType->getClassObject();
    if (classObject == nullptr || !classObject->isTypeMetadata()) {
      ObjCClassImpl impl;
      return call(&impl);
    }
  #endif
    // Otherwise, use the native Swift facilities.
    ClassImpl impl;
    return call(&impl);
  };
  switch (type->getKind()) {
    case MetadataKind::Tuple: {
      TupleImpl impl;
      return call(&impl);
    }
    case MetadataKind::Struct: {
      StructImpl impl;
      return call(&impl);
    }
    case MetadataKind::Enum:
    case MetadataKind::Optional: {
      EnumImpl impl;
      return call(&impl);
    }
    case MetadataKind::ObjCClassWrapper:
    case MetadataKind::ForeignClass:
    case MetadataKind::Class: {
      return callClass();
    }
    case MetadataKind::Metatype:
    case MetadataKind::ExistentialMetatype: {
      MetatypeImpl impl;
      return call(&impl);
    }
    case MetadataKind::Opaque: {
#if SWIFT_OBJC_INTEROP
      // If this is the AnyObject type, use the dynamic type of the
      // object reference.
      if (type == &METADATA_SYM(BO).base) {
        return callClass();
      }
#endif
      // If this is the Builtin.NativeObject type, and the heap object is a
      // class instance, use the dynamic type of the object reference.
      if (type == &METADATA_SYM(Bo).base) {
        const HeapObject *obj
          = *reinterpret_cast<const HeapObject * const*>(value);
        if (obj->metadata->getKind() == MetadataKind::Class) {
          return callClass();
        }
      }
      LLVM_FALLTHROUGH;
    }
    /// TODO: Implement specialized mirror witnesses for all kinds.
    default:
      break;
    // Types can't have these kinds.
    case MetadataKind::HeapLocalVariable:
    case MetadataKind::HeapGenericLocalVariable:
    case MetadataKind::ErrorObject:
      swift::crash("Swift mirror lookup failure");
    }
    // If we have an unknown kind of type, or a type without special handling,
    // treat it as opaque.
    OpaqueImpl impl;
    return call(&impl);
}

乍一看这个call函数代码相对有点多,其实首要便是一个大型的switch声明,和一些对特殊情况的处理,这儿重要的便是,它会用一个ReflectionMirrorImpl的子类实例去结束调用f,然后会调用这个实例上的办法去让实在的作业完结,这也便是为什么在swift_reflectionMirror_normalizedType函数中终究会return impl->type;感兴趣的能够经过源码去调试一下,这儿我也调试了,没什么指的说的,这就就不写调试过程了,下面咱们就来看看ReflectionMirrorImpl

3.2.4 ReflectionMirrorImpl

ReflectionMirrorImpl有以下6个子类:

  • TupleImpl 元组的反射
  • StructImpl 结构体的反射
  • EnumImpl 枚举的反射
  • ClassImpl 类的反射
  • MetatypeImpl 元数据的反射
  • OpaqueImpl 不透明类型的反射

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;
  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() {}
};

ReflectionMirrorImpl源码不多,可是咱们能够看到type以及count等都在其间。下面咱们以结构体为例,看看其子类的源码。

3.2.5 结构体的反射

// Implementation for structs.
struct StructImpl : ReflectionMirrorImpl {
  bool isReflectable() {
    const auto *Struct = static_cast<const StructMetadata *>(type);
    const auto &Description = Struct->getDescription();
    return Description->isReflectable();
  }
  char displayStyle() {
    return 's';
  }
  intptr_t count() {
    if (!isReflectable()) {
      return 0;
    }
    auto *Struct = static_cast<const StructMetadata *>(type);
    return Struct->getDescription()->NumFields;
  }
  intptr_t childOffset(intptr_t i) {
    auto *Struct = static_cast<const StructMetadata *>(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;
    std::tie(name, fieldInfo) = getFieldAt(type, i);
    assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
    *outName = name.data();
    *outFreeFunc = nullptr;
    return fieldInfo;
  }
  AnyReturn subscript(intptr_t i, const char **outName,
                      void (**outFreeFunc)(const char *)) {
    auto fieldInfo = childMetadata(i, outName, outFreeFunc);
    auto *bytes = reinterpret_cast<char*>(value);
    auto fieldOffset = childOffset(i);
    auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
    return copyFieldContents(fieldData, fieldInfo);
  }
};
  • 首要一个判断是否支撑反射的办法,最中是拜访的Description->isReflectable()
  • 这儿运用‘s’来显式的标明这是一个结构体
  • 然后是获取特点个数
  • 紧接着是获取每个特点的偏移值
  • 然后获取了FieldType内部还能够获取到特点的称号。
  • 终究subscript办法能够获取到特点称号和特点偏移的指针,也便是特点值。

3.3 Description

在此处咱们看到许多关于Description的代码,看来这个Description存储着许多信息,在获取Description的时分是从StructMetadata经过getDescription()办法获取到。所以这些信息根本确定是从MetaData中获取到的。StructMetadataTargetStructMetadata的别号,咱们以此为例:

3.3.1 TargetStructMetadata

TargetStructMetadata咱们能够看到如下代码:

**

const TargetStructDescriptor<Runtime> *getDescription() const {
    return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
}

说明此处会回来一个TargetStructDescriptor类型的Description,可是在这儿并没有找到这个特点,可能在父类中,咱们能够看到TargetStructMetadata承继自TargetValueMetadata

3.3.2 TargetValueMetadata

在这儿咱们能够看到如下代码:

/// An out-of-line description of the type.
TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
getDescription() const {
    return Description;
}

这儿咱们便找到了:

  • Description特点,它的类型是TargetValueTypeDescriptor,应该是TargetStructDescriptor的父类。
  • getDescription()办法,在TargetStructMetadata是重写的这个办法

3.3.3 TargetStructDescriptor

跳转到TargetStructDescriptor中后,咱们能够看到:

  • TargetValueTypeDescriptor果然是它的父类
  • 在其源码中咱们还能够发现两个特点,分别是NumFieldsFieldOffsetVectorOffset源码如下:
/// The number of stored properties in the struct.
  /// If there is a field offset vector, this is its length.
  uint32_t NumFields;
  /// The offset of the field offset vector for this struct's stored
  /// properties in its metadata, if any. 0 means there is no field offset
  /// vector.
  uint32_t FieldOffsetVectorOffset;
  • 其间NumFields首要标明结构体中特点的个数,假如只有一个字段偏移量则标明偏移量的长度
  • FieldOffsetVectorOffset标明这个结构体元数据中存储的特点的字段偏移向量的偏移量,假如是0则标明没有

3.3.4 TargetValueTypeDescriptor

源码如下,很少:

template <typename Runtime>
class TargetValueTypeDescriptor
    : public TargetTypeContextDescriptor<Runtime> {
public:
  static bool classof(const TargetContextDescriptor<Runtime> *cd) {
    return cd->getKind() == ContextDescriptorKind::Struct ||
           cd->getKind() == ContextDescriptorKind::Enum;
  }
};

在这儿咱们并没有找到太多有用的信息,咱们持续向父类寻找,其承继自TargetTypeContextDescriptor

3.3.5 TargetTypeContextDescriptor

部分源码:

template <typename Runtime>
class TargetTypeContextDescriptor
    : public TargetContextDescriptor<Runtime> {
public:
  /// The name of the type.
  TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;
  /// A pointer to the metadata access function for this type.
  ///
  /// The function type here is a stand-in. You should use getAccessFunction()
  /// to wrap the function pointer in an accessor that uses the proper calling
  /// convention for a given number of arguments.
  TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
                              /*Nullable*/ true> AccessFunctionPtr;
  /// A pointer to the field descriptor for the type, if any.
  TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
                              /*nullable*/ true> Fields;
}

咱们能够看到:

  • 该类承继自TargetContextDescriptor

  • NameAccessFunctionPtrFields三个特点

    • 其间name便是类型的称号
    • AccessFunctionPtr是该类型元数据拜访函数的指针
    • Fields是一个指向该类型的字段描绘符的指针

3.3.6 TargetContextDescriptor

接下来咱们再看看TargetTypeContextDescriptor的父类中还有什么有用的信息。部分源码如下:

/// Base class for all context descriptors.
template<typename Runtime>
struct TargetContextDescriptor {
  /// Flags describing the context, including its kind and format version.
  ContextDescriptorFlags Flags;
  /// The parent context, or null if this is a top-level context.
  TargetRelativeContextPointer<Runtime> Parent;
}

这儿咱们能够看到:

  • 这便是descriptors的基类

  • 有两个特点,分别是FlagsParent

    • 其间Flags是描绘上下文的标志,包括它的种类和格式版本。
    • Parent是记载父类上下文的,假如是尖端则为null

3.3.7 小结

至此咱们对结构体Description的层级结构根本就理清楚了,现总结如下:

Swift-反射Mirror

从上图咱们能够看到,关于一个结构体的Description来说,承继链上总共四个类,7个特点。下面咱们就对这些特点作进一步的剖析

3.4 Description中的特点

3.4.1 Flags

Flags的类型是ContextDescriptorFlags,咱们点击跳转进去,咱们能够看到:

/// Common flags stored in the first 32-bit word of any context descriptor.
struct ContextDescriptorFlags {
private:
  uint32_t Value;
  explicit constexpr ContextDescriptorFlags(uint32_t Value)
    : Value(Value) {}
public:
  constexpr ContextDescriptorFlags() : Value(0) {}
  constexpr ContextDescriptorFlags(ContextDescriptorKind kind,
                                   bool isGeneric,
                                   bool isUnique,
                                   uint8_t version,
                                   uint16_t kindSpecificFlags)
    : ContextDescriptorFlags(ContextDescriptorFlags()
                               .withKind(kind)
                               .withGeneric(isGeneric)
                               .withUnique(isUnique)
                               .withVersion(version)
                               .withKindSpecificFlags(kindSpecificFlags))
  {}
  ......
}

从以上的代码中咱们能够看到这个FLags实践是个uint32_t的值,按位存储着kindisGenericisUniqueversion等信息。

3.4.2 Parent

Parent的类型是TargetRelativeContextPointer<Runtime>,咱们看看TargetRelativeContextPointer,点击跳转过去:

using TargetRelativeContextPointer =
  RelativeIndirectablePointer<const Context<Runtime>,
                              /*nullable*/ true, int32_t,
                              TargetSignedContextPointer<Runtime, Context>>;

咱们能够看到TargetRelativeContextPointer是取自RelativeIndirectablePointer的别号,持续点击进行查看:

/// A relative reference to an object stored in memory. The reference may be
/// direct or indirect, and uses the low bit of the (assumed at least
/// 2-byte-aligned) pointer to differentiate.
template<typename ValueTy, bool Nullable = false, typename Offset = int32_t, typename IndirectType = const ValueTy *>
class RelativeIndirectablePointer {
    /// The relative offset of the pointer's memory from the `this` pointer.
    /// If the low bit is clear, this is a direct reference; otherwise, it is
    /// an indirect reference.
    Offset RelativeOffsetPlusIndirect;
        const ValueTy *get() const & {
        static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
                      "alignment of value and offset must be at least 2 to "
                      "make room for indirectable flag");
        // Check for null.
        if (Nullable && RelativeOffsetPlusIndirect == 0)
          return nullptr;
        Offset offsetPlusIndirect = RelativeOffsetPlusIndirect;
        uintptr_t address = detail::applyRelativeOffset(this,
                                                        offsetPlusIndirect & ~1);
        // If the low bit is set, then this is an indirect address. Otherwise,
        // it's direct.
        if (offsetPlusIndirect & 1) {
          return *reinterpret_cast<IndirectType const *>(address);
        } else {
          return reinterpret_cast<const ValueTy *>(address);
        }   
    }
}

依据注释咱们就能够轻松的知道这个类的首要作用是存储在内存中的目标的相对引证。这个意思在后面也有相关的解释便是在内存中引证能够是直接的也能够是间接的,直接的便是存储的绝对地址(也不一定,还有ASLR等),直接拜访这个地址就能够拿到对应的数据,而这儿的相对引证便是间接的,这儿边经过RelativeOffsetPlusIndirect特点存储相对的地址偏移量,在经过get()函数获取,在get()函数中,会调用applyRelativeOffset函数,进行地址的偏移,applyRelativeOffset源码:

**

/// Apply a relative offset to a base pointer. The offset is applied to the base
/// pointer using sign-extended, wrapping arithmetic.
template<typename BasePtrTy, typename Offset>
static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
  static_assert(std::is_integral<Offset>::value &&
                std::is_signed<Offset>::value,
                "offset type should be signed integer");
  auto base = reinterpret_cast<uintptr_t>(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;
}

终究回来的时分咱们能够看到base + extendOffset;基地址加上偏移的值,终究得到实在的地址。

3.4.2 name

name的类型是TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false>,看着应该和Parent差不多。咱们点击TargetRelativeDirectPointer跳转到它的源码处:

template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeDirectPointer
  = typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;

这儿依旧是取别号,持续跳转到RelativeDirectPointer,这儿有两个挑选,咱们挑选相对引证那个(经过注释区别)。源码如下:

/// A direct relative reference to an object that is not a function pointer.
template <typename T, bool Nullable, typename Offset>
class RelativeDirectPointer<T, Nullable, Offset,
    typename std::enable_if<!std::is_function<T>::value>::type>
    : private RelativeDirectPointerImpl<T, Nullable, Offset>
{
  using super = RelativeDirectPointerImpl<T, Nullable, Offset>;
public:
  using super::get;
  using super::super;
  RelativeDirectPointer &operator=(T *absolute) & {
    super::operator=(absolute);
    return *this;
  }
  operator typename super::PointerTy() const & {
    return this->get();
  }
  const typename super::ValueTy *operator->() const & {
    return this->get();
  }
  using super::isNull;
};

在源码中咱们能够看到许多关于supper的东西,有两处都是经过get()办法回来的,分别是PointerTyValueTy,下面咱们就来到父类办法中看看。父类是RelativeDirectPointerImpl,其部分源码如下:

/// A relative reference to a function, intended to reference private metadata
/// functions for the current executable or dynamic library image from
/// position-independent constant data.
template<typename T, bool Nullable, typename Offset>
class RelativeDirectPointerImpl {
private:
  /// The relative offset of the function's entry point from *this.
  Offset RelativeOffset;
public:
  using ValueTy = T;
  using PointerTy = T*;
  PointerTy get() const & {
    // Check for null.
    if (Nullable && RelativeOffset == 0)
      return nullptr;
    // The value is addressed relative to `this`.
    uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
    return reinterpret_cast<PointerTy>(absolute);
  }
}

这儿相同有一个Offset类型RelativeOffset,以及get()办法,相同get()办法也会调用applyRelativeOffset函数进行地址的相加,关于applyRelativeOffset办法在介绍Parent的时分说到过。

这儿边多了ValueTyPointerTyValueTy是传入泛型的值,PointerTy是其指针。

name中还有个const char,这儿是直接用const char类型存储的类型的称号。

3.4.4 AccessFunctionPtr

AccessFunctionPtr的类型是TargetRelativeDirectPointer<Runtime, MetadataResponse(...), /*Nullable*/ true>

name相同的运用偏移指针TargetRelativeDirectPointer,只不过是const char替换成了MetadataResponse(...),点击MetadataResponse跳转后咱们能够看到如下代码:

MetadataResponse() : Metadata(nullptr) {}
/// A metadata response that might not be dynamically complete.
explicit MetadataResponse(llvm::Value *metadata, llvm::Value *state,
                        MetadataState staticLowerBoundState)
  : Metadata(metadata), DynamicState(state),
    StaticState(staticLowerBoundState) {
    assert(metadata && "must be valid");
}

所以这儿仅仅一个Metadata的 指针。

3.4.5 Fields

Fields的类型是TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor, /*nullable*/ true>

TargetRelativeDirectPointer就不多说了,这儿看看FieldDescriptor点击跳转到其源码处,部分源码如下:

// Field descriptors contain a collection of field records for a single
// class, struct or enum declaration.
class FieldDescriptor {
  const FieldRecord *getFieldRecordBuffer() const {
    return reinterpret_cast<const FieldRecord *>(this + 1);
  }
public:
  const RelativeDirectPointer<const char> MangledTypeName;
  const RelativeDirectPointer<const char> Superclass;
  FieldDescriptor() = delete;
  const FieldDescriptorKind Kind;
  const uint16_t FieldRecordSize;
  const uint32_t NumFields;
}

这儿有5个特点:

  1. MangledTypeName
  2. Superclass
  3. kind
  4. FieldRecordSize
  5. NumFields

关于getFieldRecordBuffer函数的回来值FieldRecord源码如下:

class FieldRecord {
  const FieldRecordFlags Flags;
public:
  const RelativeDirectPointer<const char> MangledTypeName;
  const RelativeDirectPointer<const char> FieldName;
.....  
}

FieldRecord首要是封装了一些特点,用于存储这些值。

3.4.6 NumFields

NumFields的类型是uint32_t这就没什么好说的了,一个整形存储特点个数

3.4.7 FieldOffsetVectorOffset

FieldOffsetVectorOffset也是个uint32_t的整形,存储偏移量。

3.5 Mirror取值

关于Description剖析根本很透彻了,那么咱们就回到开始的位置,看看Mirror都是怎样从Description取出相应的值的。

3.5.1 type

首要咱们看看type是怎样取的:

首要是调用swift_reflectionMirror_normalizedType函数

**

// func _getNormalizedType<T>(_: 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; });
}

比方说这是个结构体,此刻的impl便是个StructImpl类型,所以这儿的typeStructImpl父类ReflectionMirrorImpl的特点type

3.5.2 count

关于count的获取首要是调用swift_reflectionMirror_count函数

// func _getChildCount<T>(_: T, type: Any.Type) -> Int
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
intptr_t swift_reflectionMirror_count(OpaqueValue *value,
                                      const Metadata *type,
                                      const Metadata *T) {
  return call(value, T, type, [](ReflectionMirrorImpl *impl) {
    return impl->count();
  });
}

相同还以结构体为例,此刻的implStructImpl,内部的count()函数:

intptr_t count() {
    if (!isReflectable()) {
      return 0;
    }
    auto *Struct = static_cast<const StructMetadata *>(type);
    return Struct->getDescription()->NumFields;
}

这儿的Struct便是个TargetStructMetadata类型,经过getDescription()函数获取到一个TargetStructDescriptor类型的Description,然后取NumFields的值便是咱们要的count

3.5.3 特点名和特点值

咱们知道在Mirror中经过其初始化办法回来一个供给该值子元素的AnyCollection<Child>类型的children集合,Child是一个元组(label: String?, value: Any)label是一个可选类型的特点名,value是特点值。

在剖析internalReflecting函数的时分,咱们说children是懒加载的,而加载的时分会调用getChild办法,getChild办法源码入下:

internal func getChild<T>(of value: T, type: Any.Type, index: Int) -> (label: String?, value: Any) {
  var nameC: UnsafePointer<CChar>? = nil
  var freeFunc: NameFreeFunc? = nil
  let value = _getChild(of: value, type: type, index: index, outName: &nameC, outFreeFunc: &freeFunc)
  let name = nameC.flatMap({ String(validatingUTF8: $0) })
  freeFunc?(nameC)
  return (name, value)
}

getChild办法中还会调用_getChild办法,源码如下:

@_silgen_name("swift_reflectionMirror_subscript")
internal func _getChild<T>(
  of: T,
  type: Any.Type,
  index: Int,
  outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
  outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any

_getChild办法相同是运用@_silgen_name润饰符终究调用的C++中的swift_reflectionMirror_subscript函数。

// We intentionally use a non-POD return type with this entry point to give
// it an indirect return ABI for compatibility with Swift.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
// func _getChild<T>(
//   of: T,
//   type: Any.Type,
//   index: Int,
//   outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
//   outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
// ) -> Any
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
AnyReturn swift_reflectionMirror_subscript(OpaqueValue *value, const Metadata *type,
                                           intptr_t index,
                                           const char **outName,
                                           void (**outFreeFunc)(const char *),
                                           const Metadata *T) {
  return call(value, T, type, [&](ReflectionMirrorImpl *impl) {
    return impl->subscript(index, outName, outFreeFunc);
  });
}
#pragma clang diagnostic pop

这儿咱们能够看到是调用了implsubscript函数,相同以结构体为例,咱们在StructImpl中找到该函数,源码如下:

AnyReturn subscript(intptr_t i, const char **outName,
                      void (**outFreeFunc)(const char *)) {
    auto fieldInfo = childMetadata(i, outName, outFreeFunc);
    auto *bytes = reinterpret_cast<char*>(value);
    auto fieldOffset = childOffset(i);
    auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
    return copyFieldContents(fieldData, fieldInfo);
  }

经过subscript函数咱们能够看到这儿边还会调用childMetadata获取到fieldInfo,其实这儿便是获取type,也便是特点名,经过childOffset函数和index获取到关于的偏移量,终究依据内存偏移去到特点值。

childMetadata源码:

const FieldType childMetadata(intptr_t i, const char **outName,
                                void (**outFreeFunc)(const char *)) {
    StringRef name;
    FieldType fieldInfo;
    std::tie(name, fieldInfo) = getFieldAt(type, i);
    assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
    *outName = name.data();
    *outFreeFunc = nullptr;
    return fieldInfo;
  }

这儿边的关键点是调用调用getFieldAt函数获取特点称号,

getFieldAt源码:

static std::pair<StringRef /*name*/, FieldType /*fieldInfo*/>
getFieldAt(const Metadata *base, unsigned index) {
  using namespace reflection;
  // If we failed to find the field descriptor metadata for the type, fall
  // back to returning an empty tuple as a standin.
  auto failedToFindMetadata = [&]() -> std::pair<StringRef, FieldType> {
    auto typeName = swift_getTypeName(base, /*qualified*/ true);
    missing_reflection_metadata_warning(
      "warning: the Swift runtime found no field metadata for "
      "type '%*s' that claims to be reflectable. Its fields will show up as "
      "'unknown' in Mirrors\n",
      (int)typeName.length, typeName.data);
    return {"unknown", FieldType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))};
  };
  auto *baseDesc = base->getTypeContextDescriptor();
  if (!baseDesc)
    return failedToFindMetadata();
  auto *fields = baseDesc->Fields.get();
  if (!fields)
    return failedToFindMetadata();
  auto &field = fields->getFields()[index];
  // Bounds are always valid as the offset is constant.
  auto name = field.getFieldName();
  // Enum cases don't always have types.
  if (!field.hasMangledTypeName())
    return {name, FieldType::untypedEnumCase(field.isIndirectCase())};
  auto typeName = field.getMangledTypeName();
  SubstGenericParametersFromMetadata substitutions(base);
  auto typeInfo = swift_getTypeByMangledName(MetadataState::Complete,
   typeName,
   substitutions.getGenericArgs(),
   [&substitutions](unsigned depth, unsigned index) {
     return substitutions.getMetadata(depth, index);
   },
   [&substitutions](const Metadata *type, unsigned index) {
     return substitutions.getWitnessTable(type, index);
   });
  // If demangling the type failed, pretend it's an empty type instead with
  // a log message.
  if (!typeInfo.getMetadata()) {
    typeInfo = TypeInfo({&METADATA_SYM(EMPTY_TUPLE_MANGLING),
                         MetadataState::Complete}, {});
    missing_reflection_metadata_warning(
      "warning: the Swift runtime was unable to demangle the type "
      "of field '%*s'. the mangled type name is '%*s'. this field will "
      "show up as an empty tuple in Mirrors\n",
      (int)name.size(), name.data(),
      (int)typeName.size(), typeName.data());
  }
  auto fieldType = FieldType(typeInfo.getMetadata());
  fieldType.setIndirect(field.isIndirectCase());
  fieldType.setReferenceOwnership(typeInfo.getReferenceOwnership());
  return {name, fieldType};
}

咱们能够看到在上面这个办法中:

  • 首要经过getTypeContextDescriptor获取baseDesc,也便是咱们说的Description
  • 然后经过Fields.get()获取到fields
  • 接着经过getFields()[index]或取对应的field
  • 终究经过getFieldName()函数获取到特点称号
  • getTypeContextDescriptor函数在struct TargetMetadata中,
  • 经过这个函数获取到一个TargetStructDescriptor,它的父类的父类TargetTypeContextDescriptor中的Fields特点
  • Fields特点的类型TargetRelativeDirectPointer中有get办法
  • 实践中运用的FieldDescriptor类中getFieldRecordBuffer办法回来的FieldRecord中的getFieldName函数

getFields 源码:

  const_iterator begin() const {
    auto Begin = getFieldRecordBuffer();
    auto End = Begin + NumFields;
    return const_iterator { Begin, End };
  }
  const_iterator end() const {
    auto Begin = getFieldRecordBuffer();
    auto End = Begin + NumFields;
    return const_iterator { End, End };
  }
  llvm::ArrayRef<FieldRecord> getFields() const {
    return {getFieldRecordBuffer(), NumFields};
  }

关于getFields咱们能够看到这是一块接连的空间,在beginend中:

  • begin便是getFieldRecordBuffer
  • getFieldRecordBuffer便是Begin + NumFields
  • 所以这便是一块接连内存的拜访

childOffset 源码:

剖析完了特点名的获取,咱们来看看偏移量的获取

intptr_t childOffset(intptr_t i) {
    auto *Struct = static_cast<const StructMetadata *>(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];
  }

这儿边是调用TargetStructMetadata中的getFieldOffsets函数源码如下:

/// Get a pointer to the field offset vector, if present, or null.
  const uint32_t *getFieldOffsets() const {
    auto offset = getDescription()->FieldOffsetVectorOffset;
    if (offset == 0)
      return nullptr;
    auto asWords = reinterpret_cast<const void * const*>(this);
    return reinterpret_cast<const uint32_t *>(asWords + offset);
  }

咱们能够看到这儿统一是经过获取Description中的特点,这儿运用的特点是FieldOffsetVectorOffset

获取到偏移值后经过内存偏移即可获取到特点值。

3.6 小结

至此咱们对Mirror的原理根本探究结束了,现在总结一下:

  1. Mirror经过初始化办法回来一会Mirror实例
  2. 这个实例目标依据传入目标的类型去对应的Metadata中找到Description
  3. Description能够获取name也便是特点的称号
  4. 经过内存偏移获取到特点值
  5. 还能够经过numFields获取特点的个数

下面经过该流程图总结一下swift中的mirror对结构体进行反射的首要流程

Swift-反射Mirror

关于其他类型的反射也迥然不同,还有元组、枚举、类、元数据以及不透明类型的反射,当然也有不完全支撑反射的类型,比方结构体便是不完全支撑反射的类型,感兴趣的能够持续探究一下。

  • swift中的type(of:)dump(t)便是基于Mirror的反射原理来完结的
  • Swift中的json解析结构HandyJSON的首要原理与Mirror类似,本质上便是运用metadata中的Description,经过字段的拜访,做内存的赋值。