Swift进阶-Mirror解析

Swift进阶-类与结构体
Swift-函数派发
Swift进阶-属性
Swift进阶-指针
Swift进阶-内存管理
Swift进阶-TargetClassMetadata和TargetStructMetadata数据结构源码分析
Swift进阶-Mirror解析
Swift进阶-闭包
Swift进阶-协议
Swift进阶-泛型
Swift进阶-String源码解析
Swift进阶-Array源码解析

课前知识储备
  • AnyObject代表 - 任意类的实例、类的类型、仅类遵守的协议
class Teacher {
    var age = 18
}

var t = Teacher()
var t1: AnyObject = t // 类的实例对象
var t2: AnyObject = Teacher.self // 类的类型

// 协议只允许被类遵守
protocol MyProtocol: AnyObject {
}

extension Teacher: MyProtocol {
}
  • Any:代表任意类型,包含function类型或者optional类型。
let array: [AnyObject] = [1, "aaa"] // 报错!Int是基本数据类型
let array: [Any] = [1, "aaa"] // 修改后写法
  • AnyClass: 代表任意实例对象的类型
class Teacher {
    var age = 18
}

var t: AnyClass = Teacher.self // 它属于Teacher.Type
  • type(of: T): 获取动态类型
let age = 10
// value静态类型是Any
func test(_ value: Any) {
    print(type(of: value))
}
test(age) // Int
  • T.self:如果T是实例对象,那T.self返回的是实例自己;如果T是类型,那T.self返回的是元类型。
class Teacher {
    var age = 18
}

var t = Teacher()

var t1 = t.self      // 返回的是 t
var t2 = t.self.self // 返回的是 t
var t3 = Teacher.self // 返回的是 Teacher的元类型
  • selfSelf

self的使用场景

class Teacher {
    var age = 18
    
    func test() {
        print(self) // self是当前实例对象
    }
    
    static func test1() {
        print(self) // Teacher类对象
    }
}

Self的使用场景
1.作为方法的返回类型,Self指代返回当前类的对象
2.在协议中方法返回类型 ,Self指代返回遵循这个协议的类型的对象
3.可用于使用静态属性

class Teacher {
    static let age = 18

    func test() -> Self {
        return self  // 返回当前实例对象
    }
}

class Person {
    static let age = 18
    let age1 = age
    var age2 = age
    
    lazy var age3 = Self.age
}

protocol MyProtocol {
    func get() -> Self
}

一、Mirror的基本用法

反射就是可以动态获取 类型、成员信息,在运行时可调用方法、属性 等行为的特性。
基于原生Swift使用Runtime的诸多局限性,它的标准库提供了反射机制来让我们访问成员信息。

Swift的反射机制是基于一个叫Mirror的结构体来实现的。

class Teacher {
    var age = 18
    
    func teach() {
        print("teach")
    }
}

let  t = Teacher()
let mirror = Mirror(reflecting: t)
for property in mirror.children {
    print("\(property.label!): \(property.value)")
}

// age: 18

ps: 没有办法访问到当前的函数teach,如果想要访问函数,需要把函数定义成属性信息。
那我们可以简单地封装一下,得到一个对象的key-value:

// 调用函数直接得到一个对象的key-value
func getKeyValue(_ mirrorObj: Any) -> [String: Any] {
    let mirror = Mirror(reflecting: mirrorObj)
    guard !mirror.children.isEmpty else{ return mirrorObj }
    var result: [String: Any] = [:]
    for child in mirror.children{
        if let key = child.label{
            result[key] = test(child.value)
        }else{
            print("No Keys")
        }
    }
    return result
}

然而我们还可以定义出更高级Mirror的封装

class Teacher {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}

enum JSONMapError: Error{
    case emptyKey
    case notConformProtocol
}

protocol JSONMap{
  func jsonMap() throws -> Any
}

//rethrows
extension JSONMap{
  func jsonMap() throws -> Any{
    let mirror = Mirror(reflecting: self)

    guard !mirror.children.isEmpty else{ return self }

    var result: [String: Any] = [:]

    for child in mirror.children{
       if let value = child.value as? JSONMap{
         if let key = child.label{
            result[key] = try? value.jsonMap()
          }else{
            return JSONMapError.emptyKey
          }
       }else{
           return JSONMapError.notConformProtocol
       }
    }

    return result
  }
}

extension Teacher: JSONMap{}
extension Int: JSONMap{}
extension String: JSONMap{}

// 使用:
var t = Teacher(age: 18, name: "安老师")
do {
   try t.jsonMap()
} catch {
    print(error)
}

二、Mirror源码解析

打开Swift源码搜索到Mirror.swift,很快清晰地发现Mirror是一个结构体,快速定位到初始化函数:

  public init(reflecting subject: Any) {
    if case let customized as CustomReflectable = subject {
      self = customized.customMirror
    } else {
      self = Mirror(internalReflecting: subject)
    }
  }

首先看到初始化函数接收一个 Any 参数 subject。要么subject是遵循 CustomReflectable 协议,如果是则调用 customized.customMirror得到Mirror对象,要么去创建Mirror。

我们来看一下CustomReflectable 协议具体用法:

class Teacher: CustomReflectable {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }

    var customMirror: Mirror{
        let info = KeyValuePairs<String, Any>.init(dictionaryLiteral: ("age", age),("name", name))
        let mirror = Mirror.init(self, children: info, displayStyle: .class, ancestorRepresentation: .generated)
        return mirror
    }
}

当实现这个 CustomReflectable 最直观的区别在与我们在 lldb debug 中会出现更详细的 debug 信息:

CustomReflectable

没有实现这个协议的时候就会只打印地址。
了解完CustomReflectable就需要往下了解Mirror的初始化方法 Mirror(internalReflecting: subject),全局搜索一下Mirror(internalReflecting:找到在 ReflectionMirror.swift

Mirror(internalReflecting:)

找到_getNormalizedType在哪里声明的

_getNormalizedType声明

编译器字段@_silgen_name是swift的一个隐藏符号,作用是将某个c/c++函数直接映射为swift函数。

番外知识举例 @_silgen_name 的使用:
1.新建一个 C file 文件,取名为TestC
2.在TestC.c写一个C函数实现

#include "TestC.h"
int c_add(int a, int b) {
    return a + b;
}

3.在.swift 文件声明一个映射函数

@_silgen_name("c_add")
func swift_add(a: Int32, b: Int32) -> Int32

4.直接调用 swift_add

var value = swift_add(a: 10, b: 20)
print(value)

再回到 Mirror初始化源码里边,在获取subject的真实类型信息的时候,调用了_getNormalizedType,而源码里这个函数的声明看出,实际上这个函数是在调用 swift_reflectionMirror_normalizedType 函数.

找到ReflectionMirror.cpp里边的函数名为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; });
}

它调用了一个 call函数(它返回了一个闭包),当前呢调用了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();
        }
      }
      SWIFT_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);
}

} // end anonymous namespace

可以看到call函数体里面return之前使用switch做了一系列的类型判断,来确定返回是call回调还是callClass回调

call回调

而最终所有的结果信息(type、value) 都是由当前的 ReflectionMirrorImpl 这个结构体去实现的。
看看switch里面怎么做判断的:

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

判断类型如果是 Tuple 则返回TupleImpl,如果是Struct 则返回StructImpl 等...
那如果想反射不同类型的信息,就要把要反射的类型去继承这个ReflectionMirrorImpl抽象结构体,提供具体的类型信息。

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

EnumImpl的源码声明:

// Implementation for enums.
struct EnumImpl : ReflectionMirrorImpl {
  //是否能反射
  bool isReflectable() {
    //做一个metadata的强转
    const auto *Enum = static_cast<const EnumMetadata *>(type);
    //找到metadata的Description
    const auto &Description = Enum->getDescription();
    //根据Description中的isReflectable字段来判断是否可以反射
    return Description->isReflectable();
  }
  
  const char *getInfo(unsigned *tagPtr = nullptr,
                      const Metadata **payloadTypePtr = nullptr,
                      bool *indirectPtr = nullptr) {
    // 'tag' is in the range [0..NumElements-1].
    unsigned tag = type->vw_getEnumTag(value);

    StringRef name;
    FieldType info;
    //获取FieldDescriptor的信息,也就是属性信息存放的地方
    std::tie(name, info) = getFieldAt(type, tag);
    const Metadata *payloadType = info.getType();
    bool indirect = info.isIndirect();

    if (tagPtr)
      *tagPtr = tag;
    if (payloadTypePtr)
      *payloadTypePtr = payloadType;
    if (indirectPtr)
      *indirectPtr = indirect;
    
    return name.data();
  }

  char displayStyle() override {
    return 'e';
  }
  
  //获取count
  intptr_t count() override {
    if (!isReflectable()) {
      return 0;
    }
    
    // No fields if reflecting the enumeration type instead of a case
    if (!value) {
      return 0;
    }

    const Metadata *payloadType;
    //获取挂载类型,也就是Metadata
    getInfo(nullptr, &payloadType, nullptr);
    return (payloadType != nullptr) ? 1 : 0;
  }

  ...
}

获取FieldDescriptor的信息是怎么获取的呢?
看看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))};
  };
  //获取TargetxxxDescriptor信息
  auto *baseDesc = base->getTypeContextDescriptor();
  if (!baseDesc)
    return failedToFindMetadata();

  //获取descriptor里的FieldDescriptor的信息
  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();
  ...
}
  • 此时的源码可以分析出上一篇文章Swift进阶-属性通过Mach-O找到我们的属性名称是一致的。

Mirror的工作原理:可以看出Mirro是通过Metadata(当前类型的元数据)、getDescription(当前类型的描述)、FieldDescription(当前类型属性的描述)来实现的。

三、enum数据结构还原

来看源码全局搜索在Metadata.h找到 TargetEnumMetadata的源码:

/// The structure of type metadata for enums.
template <typename Runtime>
struct TargetEnumMetadata : public TargetValueMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  using StoredSize = typename Runtime::StoredSize;
  using TargetValueMetadata<Runtime>::TargetValueMetadata;

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

  // The first trailing field of enum metadata is always the generic
  // argument array.

  /// True if the metadata records the size of the payload area.
  bool hasPayloadSize() const {
    return getDescription()->hasPayloadSizeOffset();
  }

  /// Retrieve the size of the payload area.
  ///
  /// `hasPayloadSize` must be true for this to be valid.
  StoredSize getPayloadSize() const {
    assert(hasPayloadSize());
    auto offset = getDescription()->getPayloadSizeOffset();
    const StoredSize *asWords = reinterpret_cast<const StoredSize *>(this);
    asWords += offset;
    return *asWords;
  }

  StoredSize &getPayloadSize() {
    assert(hasPayloadSize());
    auto offset = getDescription()->getPayloadSizeOffset();
    StoredSize *asWords = reinterpret_cast<StoredSize *>(this);
    asWords += offset;
    return *asWords;
  }

  bool isStaticallySpecializedGenericMetadata() const {
    auto *description = getDescription();
    if (!description->isGeneric())
      return false;

    auto *trailingFlags = getTrailingFlags();
    if (trailingFlags == nullptr)
      return false;

    return trailingFlags->isStaticSpecialization();
  }

  bool isCanonicalStaticallySpecializedGenericMetadata() const {
    auto *description = getDescription();
    if (!description->isGeneric())
      return false;

    auto *trailingFlags = getTrailingFlags();
    if (trailingFlags == nullptr)
      return false;

    return trailingFlags->isCanonicalStaticSpecialization();
  }

  const MetadataTrailingFlags *getTrailingFlags() const {
    auto description = getDescription();
    auto flags = description->getFullGenericContextHeader()
                     .DefaultInstantiationPattern->PatternFlags;
    if (!flags.hasTrailingFlags())
      return nullptr;
    auto offset =
        getGenericArgumentOffset() +
        description->getFullGenericContextHeader().Base.getNumArguments() +
        (hasPayloadSize() ? 1 : 0);
    auto asWords = reinterpret_cast<const void *const *>(this);
    return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
  }

  static constexpr int32_t getGenericArgumentOffset() {
    return sizeof(TargetEnumMetadata<Runtime>) / sizeof(StoredPointer);
  }

  static bool classof(const TargetMetadata<Runtime> *metadata) {
    return metadata->getKind() == MetadataKind::Enum
      || metadata->getKind() == MetadataKind::Optional;
  }
};
using EnumMetadata = TargetEnumMetadata<InProcess>;

继承自TargetValueMetadata

/// The common structure of metadata for structs and enums.
template <typename Runtime>
struct TargetValueMetadata : public TargetMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  TargetValueMetadata(MetadataKind Kind,
                      const TargetTypeContextDescriptor<Runtime> *description)
      : TargetMetadata<Runtime>(Kind), Description(description) {}

  /// An out-of-line description of the type.
  TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;

  static bool classof(const TargetMetadata<Runtime> *metadata) {
    return metadata->getKind() == MetadataKind::Struct
      || metadata->getKind() == MetadataKind::Enum
      || metadata->getKind() == MetadataKind::Optional;
  }

  ConstTargetMetadataPointer<Runtime, TargetValueTypeDescriptor>
  getDescription() const {
    return Description;
  }

  typename Runtime::StoredSignedPointer
  getDescriptionAsSignedPointer() const {
    return Description;
  }
};
using ValueMetadata = TargetValueMetadata<InProcess>;

继承自TargetMetadata:

template <typename Runtime>
struct TargetMetadata {
  using StoredPointer = typename Runtime::StoredPointer;

  /// The basic header type.
  typedef TargetTypeMetadataHeader<Runtime> HeaderType;

  constexpr TargetMetadata()
    : Kind(static_cast<StoredPointer>(MetadataKind::Class)) {}
  constexpr TargetMetadata(MetadataKind Kind)
    : Kind(static_cast<StoredPointer>(Kind)) {}

#if SWIFT_OBJC_INTEROP
protected:
  constexpr TargetMetadata(TargetAnyClassMetadataObjCInterop<Runtime> *isa)
    : Kind(reinterpret_cast<StoredPointer>(isa)) {}
#endif

private:
  /// The kind. Only valid for non-class metadata; getKind() must be used to get
  /// the kind value.
  StoredPointer Kind;
public:
  /// Get the metadata kind.
  MetadataKind getKind() const {
    return getEnumeratedMetadataKind(Kind);
  }
  
  /// Set the metadata kind.
  void setKind(MetadataKind kind) {
    Kind = static_cast<StoredPointer>(kind);
  }

protected:
  const TargetAnyClassMetadata<Runtime> *getClassISA() const {
    return reinterpret_cast<const TargetAnyClassMetadata<Runtime> *>(Kind);
  }
  void setClassISA(const TargetAnyClassMetadata<Runtime> *isa) {
    Kind = reinterpret_cast<StoredPointer>(isa);
  }

public:
  /// Is this a class object--the metadata record for a Swift class (which also
  /// serves as the class object), or the class object for an ObjC class (which
  /// is not metadata)?
  bool isClassObject() const {
    return static_cast<MetadataKind>(getKind()) == MetadataKind::Class;
  }
  
  /// Does the given metadata kind represent metadata for some kind of class?
  static bool isAnyKindOfClass(MetadataKind k) {
    switch (k) {
    case MetadataKind::Class:
    case MetadataKind::ObjCClassWrapper:
    case MetadataKind::ForeignClass:
      return true;

    default:
      return false;
    }
  }
  
  /// Is this metadata for an existential type?
  bool isAnyExistentialType() const {
    switch (getKind()) {
    case MetadataKind::ExistentialMetatype:
    case MetadataKind::Existential:
      return true;

    default:
      return false;
    }
  }
  
  /// Is this either type metadata or a class object for any kind of class?
  bool isAnyClass() const {
    return isAnyKindOfClass(getKind());
  }

  const ValueWitnessTable *getValueWitnesses() const {
    return asFullMetadata(this)->ValueWitnesses;
  }

  const TypeLayout *getTypeLayout() const {
    return getValueWitnesses()->getTypeLayout();
  }

  void setValueWitnesses(const ValueWitnessTable *table) {
    asFullMetadata(this)->ValueWitnesses = table;
  }
  
  // Define forwarders for value witnesses. These invoke this metadata's value
  // witness table with itself as the 'self' parameter.
  #define WANT_ONLY_REQUIRED_VALUE_WITNESSES
  #define FUNCTION_VALUE_WITNESS(WITNESS, UPPER, RET_TYPE, PARAM_TYPES)    \
    template<typename...A>                                                 \
    _ResultOf<ValueWitnessTypes::WITNESS ## Unsigned>::type                            \
    vw_##WITNESS(A &&...args) const {                                      \
      return getValueWitnesses()->WITNESS(std::forward<A>(args)..., this); \
    }
  #define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE)
  #include "swift/ABI/ValueWitness.def"

  unsigned vw_getEnumTag(const OpaqueValue *value) const {
    return getValueWitnesses()->_asEVWT()->getEnumTag(const_cast<OpaqueValue*>(value), this);
  }
  void vw_destructiveProjectEnumData(OpaqueValue *value) const {
    getValueWitnesses()->_asEVWT()->destructiveProjectEnumData(value, this);
  }
  void vw_destructiveInjectEnumTag(OpaqueValue *value, unsigned tag) const {
    getValueWitnesses()->_asEVWT()->destructiveInjectEnumTag(value, tag, this);
  }

  size_t vw_size() const {
    return getValueWitnesses()->getSize();
  }

  size_t vw_alignment() const {
    return getValueWitnesses()->getAlignment();
  }

  size_t vw_stride() const {
    return getValueWitnesses()->getStride();
  }

  unsigned vw_getNumExtraInhabitants() const {
    return getValueWitnesses()->getNumExtraInhabitants();
  }

  /// Allocate an out-of-line buffer if values of this type don't fit in the
  /// ValueBuffer.
  /// NOTE: This is not a box for copy-on-write existentials.
  OpaqueValue *allocateBufferIn(ValueBuffer *buffer) const;

  /// Get the address of the memory previously allocated in the ValueBuffer.
  /// NOTE: This is not a box for copy-on-write existentials.
  OpaqueValue *projectBufferFrom(ValueBuffer *buffer) const;

  /// Deallocate an out-of-line buffer stored in 'buffer' if values of this type
  /// are not stored inline in the ValueBuffer.
  void deallocateBufferIn(ValueBuffer *buffer) const;

  // Allocate an out-of-line buffer box (reference counted) if values of this
  // type don't fit in the ValueBuffer.
  // NOTE: This *is* a box for copy-on-write existentials.
  OpaqueValue *allocateBoxForExistentialIn(ValueBuffer *Buffer) const;

  // Deallocate an out-of-line buffer box if one is present.
  void deallocateBoxForExistentialIn(ValueBuffer *Buffer) const;

  /// Get the nominal type descriptor if this metadata describes a nominal type,
  /// or return null if it does not.
  ConstTargetMetadataPointer<Runtime, TargetTypeContextDescriptor>
  getTypeContextDescriptor() const {
    switch (getKind()) {
    case MetadataKind::Class: {
      if (Runtime::ObjCInterop) {
        const auto cls = static_cast<const TargetClassMetadata<
            Runtime, TargetAnyClassMetadataObjCInterop<Runtime>> *>(this);
        if (!cls->isTypeMetadata())
          return nullptr;
        if (cls->isArtificialSubclass())
          return nullptr;
        return cls->getDescription();
      } else {
        const auto cls = static_cast<const TargetClassMetadata<
            Runtime, TargetAnyClassMetadata<Runtime>> *>(this);
        if (!cls->isTypeMetadata())
          return nullptr;
        if (cls->isArtificialSubclass())
          return nullptr;
        return cls->getDescription();
      }
    }
    case MetadataKind::Struct:
    case MetadataKind::Enum:
    case MetadataKind::Optional:
      return static_cast<const TargetValueMetadata<Runtime> *>(this)
          ->Description;
    case MetadataKind::ForeignClass:
      return static_cast<const TargetForeignClassMetadata<Runtime> *>(this)
          ->Description;
    default:
      return nullptr;
    }
  }

  /// Get the class object for this type if it has one, or return null if the
  /// type is not a class (or not a class with a class object).
  const typename Runtime::template TargetClassMetadata<Runtime> *
  getClassObject() const;

  /// Retrieve the generic arguments of this type, if it has any.
  ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *
  getGenericArgs() const {
    auto description = getTypeContextDescriptor();
    if (!description)
      return nullptr;

    auto generics = description->getGenericContext();
    if (!generics)
      return nullptr;

    auto asWords = reinterpret_cast<
      ConstTargetMetadataPointer<Runtime, swift::TargetMetadata> const *>(this);
    return asWords + description->getGenericArgumentOffset();
  }

  bool satisfiesClassConstraint() const;

  const TypeContextDescriptor *getDescription() const;

  bool isStaticallySpecializedGenericMetadata() const;

  bool isCanonicalStaticallySpecializedGenericMetadata() const;

#if SWIFT_OBJC_INTEROP
  /// Get the ObjC class object for this type if it has one, or return null if
  /// the type is not a class (or not a class with a class object).
  /// This is allowed for InProcess values only.
  template <typename R = Runtime>
  typename std::enable_if<std::is_same<R, InProcess>::value, Class>::type
  getObjCClassObject() const {
    return reinterpret_cast<Class>(
        const_cast<TargetClassMetadata<
            InProcess, TargetAnyClassMetadataObjCInterop<InProcess>> *>(
            getClassObject()));
  }
#endif

#ifndef NDEBUG
  LLVM_ATTRIBUTE_DEPRECATED(void dump() const,
                            "Only meant for use in the debugger");
#endif

protected:
  friend struct TargetOpaqueMetadata<Runtime>;
  
  /// Metadata should not be publicly copied or moved.
  constexpr TargetMetadata(const TargetMetadata &) = default;
  TargetMetadata &operator=(const TargetMetadata &) = default;
  constexpr TargetMetadata(TargetMetadata &&) = default;
  TargetMetadata &operator=(TargetMetadata &&) = default;
};

TargetEnumMetadata 继承于 TargetValueMetadata 继承于 TargetMetadata; 同时要注意 TargetRelativeDirectPointer数据结构是相对地址信息 - 存储的是偏移量。(只粘贴了部分源码,自行下载源码看着分析就得出)

TargetEnumMetadata的数据结构:

// 枚举Metadata
struct TargetEnumMetadata {
    var kind: Int
    var typeDescriptor: UnsafeMutablePointer<TargetEnumDescriptor>
}

// 枚举描述器
struct TargetEnumDescriptor {
    var flags: Int32
    var parent: TargetRelativeDirectPointer<UnsafeRawPointer>
    var name: TargetRelativeDirectPointer<CChar>
    var accessFunctionPointer: TargetRelativeDirectPointer<UnsafeRawPointer>
    var fieldDescriptor: TargetRelativeDirectPointer<FieldDescriptor>
    var NumPayloadCasesAndPayloadSizeOffset: UInt32
    var NumEmptyCases: UInt32
}
// 相对地址信息
struct TargetRelativeDirectPointer<Pointee> {
    var offset: Int32 // 存储偏移量
    
    // 获取相对偏移指针
    mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee>{
        let offset = self.offset
        
        return withUnsafePointer(to: &self) { p in
           return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))
        }
    }
}
// 属性描述器
struct FieldDescriptor {
    var MangledTypeName: TargetRelativeDirectPointer<CChar> 
    var Superclass: TargetRelativeDirectPointer<CChar>
    var kind: UInt16
    var fieldRecordSize: Int16
    var numFields: Int32 // 属性个数
    var fields: FiledRecordBuffer<FieldRecord> // 属性列表
}

// 属性
struct FieldRecord {
    var fieldRecordFlags: Int32 // flags
    var mangledTypeName: TargetRelativeDirectPointer<CChar> // 属性类型
    var fieldName: TargetRelativeDirectPointer<UInt8> // 属性名称
}

struct FiledRecordBuffer<Element>{
    var element: Element
    
    mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
        return withUnsafePointer(to: &self) {
            let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
                return start
            }
            return UnsafeBufferPointer(start: ptr, count: n)
        }
    }
    
    mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
        return withUnsafePointer(to: &self) {
            return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
        }
    }
}

注意:TargetRelativeDirectPointer是相对地址信息,比如说TargetEnumDescriptor里的name存储的是相对于当前对象的偏移量,通过这个偏移量找到真实的内容

那么我们设计出了EnumMetadata,该如何使用呢?请看举例:
自定义一个枚举类 TerminalChar

enum TerminalChar {
    case plain(Bool)
    case bold
    case empty
    case cursor
}

通过按位转换成指针 UnsafeMutablePointer<TargetEnumMetadata>,就可以对指针进行操作了(给个小案例叭,请自己运行看结果):

// 元类 Metadata
// var clazz = TerminalChar.self
// 使用按位转换成指针去操作(当前的元类clazz 就是 TargetEnumMetadata 这个结构体)
let enumMetadata_ptr = unsafeBitCast(TerminalChar.self as Any.Type, to: UnsafeMutablePointer<TargetEnumMetadata>.self)

let namePtr = enumMetadata_ptr.pointee.typeDescriptor.pointee.name.getmeasureRelativeOffset()
print(String(cString: namePtr)) // TerminalChar
print(enumMetadata_ptr.pointee.typeDescriptor.pointee.NumPayloadCasesAndPayloadSizeOffset) // 1
print(enumMetadata_ptr.pointee.typeDescriptor.pointee.NumEmptyCases) // 3

// 拿到属性描述器指针
let fieldDesc_ptr = enumMetadata_ptr.pointee.typeDescriptor.pointee.fieldDescriptor.getmeasureRelativeOffset()
print(String(cString: fieldDesc_ptr.pointee.MangledTypeName.getmeasureRelativeOffset()))
print(String(cString: fieldDesc_ptr.pointee.Superclass.getmeasureRelativeOffset()))
print(fieldDesc_ptr.pointee.kind) // 2
print(fieldDesc_ptr.pointee.fieldRecordSize) // 12
print(fieldDesc_ptr.pointee.numFields) // 4
print(String(cString: fieldDesc_ptr.pointee.fields.index(of: 0).pointee.fieldName.getmeasureRelativeOffset())) // plain

注意:
let enumMetadata_ptr = unsafeBitCast(clazz as Any.Type, to: UnsafeMutablePointer<TargetEnumMetadata>.self)这句代码为什么一定要把 TerminalChar.self 强转成 Any.Type

unsafeBitCast需要两个参数的内存大小相同。必须使用:TerminalChar.self as Any.Type进行转换,因为根据测试发现TerminalChar.self获取内存大小为0(这个地方是真的坑),先来看看MemoryLayout输出结果:

番外小知识 unsafeBitCast 举例

var age = 10
var age1 = unsafeBitCast(age, to: Double.self)
print(age1) // 5e-323

注意:unsafeBitCast(age, to: Double.self)中的age是以二进制位的方式塞进Double类型里边,本质上age1上存储的是0xa,当print(age1)的时候是输出科学技术的Double。来看看 x/8g 后的 age1:

unsafeBitCast

言归正传!上面那个小案例可以把TerminalCharenum类的属性输出出来了,试想一下,我们是不是可以从源码得出StructMetadata,从而把一个结构体对象的属性内容打印出来。

如果你想学习ClassMetadataStructMetadata和更详细的EnumMetadata,可以查看我分享的这篇文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容