Swift進階-Mirror解析

Swift進階-類與結(jié)構(gòu)體
Swift-函數(shù)派發(fā)
Swift進階-屬性
Swift進階-指針
Swift進階-內(nèi)存管理
Swift進階-TargetClassMetadata和TargetStructMetadata數(shù)據(jù)結(jié)構(gòu)源碼分析
Swift進階-Mirror解析
Swift進階-閉包
Swift進階-協(xié)議
Swift進階-泛型
Swift進階-String源碼解析
Swift進階-Array源碼解析

課前知識儲備
  • AnyObject代表 - 任意類的實例沿癞、類的類型杯活、僅類遵守的協(xié)議
class Teacher {
    var age = 18
}

var t = Teacher()
var t1: AnyObject = t // 類的實例對象
var t2: AnyObject = Teacher.self // 類的類型

// 協(xié)議只允許被類遵守
protocol MyProtocol: AnyObject {
}

extension Teacher: MyProtocol {
}
  • Any:代表任意類型,包含function類型或者optional類型谴咸。
let array: [AnyObject] = [1, "aaa"] // 報錯!Int是基本數(shù)據(jù)類型
let array: [Any] = [1, "aaa"] // 修改后寫法
  • AnyClass: 代表任意實例對象的類型
class Teacher {
    var age = 18
}

var t: AnyClass = Teacher.self // 它屬于Teacher.Type
  • type(of: T): 獲取動態(tài)類型
let age = 10
// value靜態(tài)類型是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是當(dāng)前實例對象
    }
    
    static func test1() {
        print(self) // Teacher類對象
    }
}

Self的使用場景
1.作為方法的返回類型珊随,Self指代返回當(dāng)前類的對象
2.在協(xié)議中方法返回類型 ,Self指代返回遵循這個協(xié)議的類型的對象
3.可用于使用靜態(tài)屬性

class Teacher {
    static let age = 18

    func test() -> Self {
        return self  // 返回當(dāng)前實例對象
    }
}

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

protocol MyProtocol {
    func get() -> Self
}

一、Mirror的基本用法

反射就是可以動態(tài)獲取 類型叶洞、成員信息鲫凶,在運行時可調(diào)用方法、屬性 等行為的特性衩辟。
基于原生Swift使用Runtime的諸多局限性螟炫,它的標(biāo)準(zhǔn)庫提供了反射機制來讓我們訪問成員信息。

Swift的反射機制是基于一個叫Mirror的結(jié)構(gòu)體來實現(xiàn)的惭婿。

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: 沒有辦法訪問到當(dāng)前的函數(shù)teach不恭,如果想要訪問函數(shù),需要把函數(shù)定義成屬性信息财饥。
那我們可以簡單地封裝一下换吧,得到一個對象的key-value:

// 調(diào)用函數(shù)直接得到一個對象的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钥星,很快清晰地發(fā)現(xiàn)Mirror是一個結(jié)構(gòu)體沾瓦,快速定位到初始化函數(shù):

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

首先看到初始化函數(shù)接收一個 Any 參數(shù) subject。要么subject是遵循 CustomReflectable 協(xié)議谦炒,如果是則調(diào)用 customized.customMirror得到Mirror對象贯莺,要么去創(chuàng)建Mirror。

我們來看一下CustomReflectable 協(xié)議具體用法:

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
    }
}

當(dāng)實現(xiàn)這個 CustomReflectable 最直觀的區(qū)別在與我們在 lldb debug 中會出現(xiàn)更詳細(xì)的 debug 信息:

CustomReflectable

沒有實現(xiàn)這個協(xié)議的時候就會只打印地址宁改。
了解完CustomReflectable就需要往下了解Mirror的初始化方法 Mirror(internalReflecting: subject)缕探,全局搜索一下Mirror(internalReflecting:找到在 ReflectionMirror.swift

Mirror(internalReflecting:)

找到_getNormalizedType在哪里聲明的

_getNormalizedType聲明

編譯器字段@_silgen_name是swift的一個隱藏符號,作用是將某個c/c++函數(shù)直接映射為swift函數(shù)还蹲。

番外知識舉例 @_silgen_name 的使用:
1.新建一個 C file 文件爹耗,取名為TestC
2.在TestC.c寫一個C函數(shù)實現(xiàn)

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

3.在.swift 文件聲明一個映射函數(shù)

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

4.直接調(diào)用 swift_add

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

再回到 Mirror初始化源碼里邊,在獲取subject的真實類型信息的時候谜喊,調(diào)用了_getNormalizedType潭兽,而源碼里這個函數(shù)的聲明看出,實際上這個函數(shù)是在調(diào)用 swift_reflectionMirror_normalizedType 函數(shù).

找到ReflectionMirror.cpp里邊的函數(shù)名為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; });
}

它調(diào)用了一個 call函數(shù)(它返回了一個閉包)斗遏,當(dāng)前呢調(diào)用了call函數(shù)返回了類型信息山卦。

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函數(shù)體里面return之前使用switch做了一系列的類型判斷,來確定返回是call回調(diào)還是callClass回調(diào)

call回調(diào)

而最終所有的結(jié)果信息(type诵次、value) 都是由當(dāng)前的 ReflectionMirrorImpl 這個結(jié)構(gòu)體去實現(xiàn)的账蓉。
看看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抽象結(jié)構(gòu)體剔猿,提供具體的類型信息。

ReflectionMirrorImpl是反射實現(xiàn)的抽象基類:

// 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的強轉(zhuǎn)
    const auto *Enum = static_cast<const EnumMetadata *>(type);
    //找到metadata的Description
    const auto &Description = Enum->getDescription();
    //根據(jù)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(當(dāng)前類型的元數(shù)據(jù))汪茧、getDescription(當(dāng)前類型的描述)、FieldDescription(當(dāng)前類型屬性的描述)來實現(xiàn)的限番。

三舱污、enum數(shù)據(jù)結(jié)構(gòu)還原

來看源碼全局搜索在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數(shù)據(jù)結(jié)構(gòu)是相對地址信息 - 存儲的是偏移量。(只粘貼了部分源碼弥虐,自行下載源碼看著分析就得出)

TargetEnumMetadata的數(shù)據(jù)結(jié)構(gòu):

// 枚舉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 // 屬性個數(shù)
    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存儲的是相對于當(dāng)前對象的偏移量,通過這個偏移量找到真實的內(nèi)容霜瘪。

那么我們設(shè)計出了EnumMetadata珠插,該如何使用呢?請看舉例:
自定義一個枚舉類 TerminalChar

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

通過按位轉(zhuǎn)換成指針 UnsafeMutablePointer<TargetEnumMetadata>颖对,就可以對指針進行操作了(給個小案例叭捻撑,請自己運行看結(jié)果):

// 元類 Metadata
// var clazz = TerminalChar.self
// 使用按位轉(zhuǎn)換成指針去操作(當(dāng)前的元類clazz 就是 TargetEnumMetadata 這個結(jié)構(gòu)體)
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 強轉(zhuǎn)成 Any.Type

unsafeBitCast需要兩個參數(shù)的內(nèi)存大小相同缤底。必須使用:TerminalChar.self as Any.Type進行轉(zhuǎn)換顾患,因為根據(jù)測試發(fā)現(xiàn)TerminalChar.self獲取內(nèi)存大小為0(這個地方是真的坑),先來看看MemoryLayout輸出結(jié)果:

番外小知識 unsafeBitCast 舉例

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

注意:unsafeBitCast(age, to: Double.self)中的age是以二進制位的方式塞進Double類型里邊个唧,本質(zhì)上age1上存儲的是0xa江解,當(dāng)print(age1)的時候是輸出科學(xué)技術(shù)的Double。來看看 x/8g 后的 age1:

unsafeBitCast

言歸正傳徙歼!上面那個小案例可以把TerminalCharenum類的屬性輸出出來了犁河,試想一下,我們是不是可以從源碼得出StructMetadata鲁沥,從而把一個結(jié)構(gòu)體對象的屬性內(nèi)容打印出來呼股。

如果你想學(xué)習(xí)ClassMetadataStructMetadata和更詳細(xì)的EnumMetadata画恰,可以查看我分享的這篇文章彭谁。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市允扇,隨后出現(xiàn)的幾起案子缠局,更是在濱河造成了極大的恐慌,老刑警劉巖考润,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狭园,死亡現(xiàn)場離奇詭異,居然都是意外死亡糊治,警方通過查閱死者的電腦和手機唱矛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绎谦,你說我怎么就攤上這事管闷。” “怎么了窃肠?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵包个,是天一觀的道長。 經(jīng)常有香客問我冤留,道長碧囊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任纤怒,我火速辦了婚禮糯而,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肪跋。我一直安慰自己歧蒋,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布州既。 她就那樣靜靜地躺著谜洽,像睡著了一般。 火紅的嫁衣襯著肌膚如雪吴叶。 梳的紋絲不亂的頭發(fā)上阐虚,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音蚌卤,去河邊找鬼实束。 笑死,一個胖子當(dāng)著我的面吹牛逊彭,可吹牛的內(nèi)容都是我干的咸灿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼侮叮,長吁一口氣:“原來是場噩夢啊……” “哼避矢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起囊榜,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤审胸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后卸勺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體砂沛,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年曙求,在試婚紗的時候發(fā)現(xiàn)自己被綠了碍庵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片映企。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖静浴,靈堂內(nèi)的尸體忽然破棺而出卑吭,到底是詐尸還是另有隱情,我是刑警寧澤马绝,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站挣菲,受9級特大地震影響富稻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜白胀,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一椭赋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧或杠,春花似錦哪怔、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至挟鸠,卻和暖如春叉信,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背艘希。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工硼身, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人覆享。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓佳遂,卻偏偏與公主長得像,于是被迫代替她去往敵國和親撒顿。 傳聞我的和親對象是個殘疾皇子丑罪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容