Swift底層原理-Mirror

Swift底層原理-Mirror

  • 反射:是指可以動態(tài)獲取類型、成員信息,在運行時可以調(diào)用方法、屬性等行為的特性。

  • 對于一個純swift類來說,并不支持直接像OC runtime那樣的操作,但是swift標(biāo)準(zhǔn)庫依舊提供了反射機制,用來訪問成員信息,即Mirror

  • 在使?OC開發(fā)時很少強調(diào)其反射概念,因為OCRuntime要?其他語?中的反射強?的多。但是Swift是??類型 安全的語?,不?持我們像OC那樣直接操作,它的標(biāo)準(zhǔn)庫仍然提供了反射機制來讓我們訪問成員信息。

Mirror簡介

  • MirrorSwift中的反射機制的實現(xiàn),它的本質(zhì)是一個結(jié)構(gòu)體。
public struct Mirror {

    /// 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 typealias Children = AnyCollection<Mirror.Child>
    /*
    public enum DisplayStyle : Sendable {
        case `struct`
        case `class`
        case `enum`
        case tuple
        case optional
        case collection
        case dictionary
        case set
    }
    */
    public let children: Mirror.Children

    /// A suggested display style for the reflected subject.
    public let displayStyle: Mirror.DisplayStyle?
    
    /// A mirror of the subject's superclass, if one exists.
    public var superclassMirror: Mirror? { get }
    
    // 省略部分方法
}
  • subjectType:表示類型,被反射主體的類型
  • children:子元素集合
  • displayStyle:顯示類型,基本類型為nil
  • superclassMirror:父類反射, 沒有父類為nil

Mirror簡單使用

  • 我們通過Mirror打印對象的屬性名稱和值
class Test {
    var age: Int = 18
    var name: String = "ssl"
}

var t = Test()

var mirror = Mirror(reflecting: t.self)
print("對象類型:\(mirror.subjectType)")
print("對象屬性個數(shù):\(mirror.children.count)")
print("對象的屬性及屬性值")
for child in mirror.children {
    print("\(child.label!)---\(child.value)")
}
  • 打印結(jié)果
對象類型:Test
對象屬性個數(shù):2
對象的屬性及屬性值
age---18
name---ssl

Mirror源碼

  • 為什么通過Mirror就可以獲得對象的屬性信息?我們通過源碼來探索它做了哪些事情

  • 在源碼中找到Mirror.swift,快速定位到Mirror的初始化方法,如下:

public init(reflecting subject: Any) {
    if case let customized as CustomReflectable = subject {
        self = customized.customMirror
    } else {
        self = Mirror(internalReflecting: subject)
    }
}
  • 在初始化函數(shù)中判斷subject是否遵守CustomReflectable協(xié)議,遵守協(xié)議的實例,直接調(diào)用customMirror屬性。
  • 如果沒有遵守該協(xié)議,則走默認(rèn)初始化流程Mirror(internalReflecting: subject)

初始化

internal init(internalReflecting subject: Any,
              subjectType: Any.Type? = nil,
              customAncestor: Mirror? = nil)
{
    // 1. 判斷實例對象的類型,如果為nil,則通過_getNormalizedType去獲取
    let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
    
    // 2. 獲取成員變量
    let childCount = _getChildCount(subject, type: subjectType)
    let children = (0 ..< childCount).lazy.map({
      getChild(of: subject, type: subjectType, index: $0)
    })
    self.children = Children(children)
    
    // 3. 獲取父類的Mirror
    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)
    }
    
    // 4. 設(shè)置 displayStyle
    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)'")
    }
    
    // 5. 設(shè)置 subjectType 和 _defaultDescendantRepresentation
    self.subjectType = subjectType
    self._defaultDescendantRepresentation = .generated
  }
}
  • 在該方法中,主要做了一下幾件事:
    1. 獲取subjectType,如果傳入的有值就使用傳入的值,否則就通過_getNormalizedType函數(shù)去獲取
    2. 通過_getChildCount獲取childCount,然后獲取children,注意這里是懶加載的
    3. 針對父類SuperclassMirror處理
    4. 最后會獲取并解析顯示的樣式,并設(shè)置Mirror一些其他屬性。

_getNormalizedType

  • 我們首先看一下,是如果獲取實例對象的類型
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
  • 函數(shù)上面使用了一個編譯字段 @_silgen_name,這個是Swift的一個隱藏符號,作?是將某個 C/C++ 函數(shù)直接映射為 Swift 函數(shù)。也就是我們在調(diào)用 _getNormalizedType 函數(shù)的時候,本質(zhì)上是在調(diào)用 swift_reflectionMirror_normalizedType 函數(shù)。
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
                                                      const Metadata *type,
                                                      const Metadata *T) {
  return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}
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;
  }
  
  // 這里是類似swift的閉包
  // 非類類型的調(diào)用
  auto call = [&](ReflectionMirrorImpl *impl) {
    impl->type = type;
    impl->value = value;
    auto result = f(impl);
    return result;
  };
  
  // 類類型的調(diào)用
  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);
  };
  
  // 通過傳入類型的kind來判斷,返回不同類型imp
  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);
}
  • 該方法比較長,但是邏輯比較清晰。主要做了兩件事:

    1. 根據(jù) kind 來判斷實例的類型,從而拿到不同類型對應(yīng)的 impl
    2. 如果類型不是類類型,則調(diào)用非類的 call(&impl);類是調(diào)用 callClass。
  • 最終通過閉包返回一個ReflectionMirrorImpl類型的成員變量出去。

ReflectionMirrorImpl

ReflectionMirrorImpl有以下6個子類:

  • TupleImpl元組的反射
  • StructImpl結(jié)構(gòu)體的反射
  • EnumImpl枚舉的反射
  • ClassImpl類的反射
  • MetatypeImpl元數(shù)據(jù)的反射
  • OpaqueImpl不透明類型的反射
  • 我們首先看一下ReflectionMirrorImpl結(jié)構(gòu)
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() {}
};
  • 里面包含了metedata、count等一些信息。這里也可以理解,上面swift_reflectionMirror_normalizedType方法中,最終在call函數(shù)的閉包中返回了imp->type,把類型信息返回出去了
  • 這里我們以結(jié)構(gòu)體子類為例子,查看它源碼

StructImpl

struct StructImpl : ReflectionMirrorImpl {
  // 是否支持反射
  bool isReflectable() {
    const auto *Struct = static_cast<const StructMetadata *>(type);
    const auto &Description = Struct->getDescription();
    return Description->isReflectable();
  }
  
  // 表明是一個結(jié)構(gòu)體
  char displayStyle() {
    return 's';
  }
  
  // 屬性個數(shù)
  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);
  }
};
  • 在該結(jié)構(gòu)內(nèi)提供了獲取屬性、屬性信息等一些方法
  • 但是這些方法內(nèi)部,都是通過StructMetadatagetDescription方法來獲取對應(yīng)的一些信息

Description

  • StructImpl中我們看到很多關(guān)于Description的代碼,看來這個Description存儲著很多信息,在獲取Description的時候是從StructMetadata通過getDescription()方法獲取到。
  • 這里我們還是以研究結(jié)構(gòu)體的metadata為例子
using StructMetadata = TargetStructMetadata<InProcess>;
  • StructMetadataTargetStructMetadata的別名

TargetStructMetadata

template <typename Runtime>
struct TargetStructMetadata : public TargetValueMetadata<Runtime> {
  using StoredPointer = typename Runtime::StoredPointer;
  using TargetValueMetadata<Runtime>::TargetValueMetadata;

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

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

  /// 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);
  }

  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 fieldOffset = description->FieldOffsetVectorOffset;
    auto offset =
        fieldOffset +
        // Pad to the nearest pointer.
        ((description->NumFields * sizeof(uint32_t) + sizeof(void *) - 1) /
         sizeof(void *));
    auto asWords = reinterpret_cast<const void *const *>(this);
    return reinterpret_cast<const MetadataTrailingFlags *>(asWords + offset);
  }

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

  static bool classof(const TargetMetadata<Runtime> *metadata) {
    return metadata->getKind() == MetadataKind::Struct;
  }
};
  • 我們在第一個方法可以看到,TargetStructDescriptor類型的Description
  • 在本類沒有屬性相關(guān),我們?nèi)ニ母割?code>TargetValueMetadata查看一下

TargetValueMetadata

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;
  }
};
  • 這里我們便找到了Description屬性,它的類型是TargetValueTypeDescriptor,應(yīng)該是TargetStructDescriptor的父類。
  • getDescription()方法,在TargetStructMetadata是重寫的這個方法

TargetStructDescriptor

  • 跳轉(zhuǎn)到TargetStructDescriptor中后,我們可以看到
template <typename Runtime>
class TargetStructDescriptor final
    : public TargetValueTypeDescriptor<Runtime>,
      public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
                            TargetTypeGenericContextDescriptorHeader,
                            /*additional trailing objects*/
                            TargetForeignMetadataInitialization<Runtime>,
                            TargetSingletonMetadataInitialization<Runtime>> {
  // 省略部分方法

public:
  using TrailingGenericContextObjects::getGenericContext;
  using TrailingGenericContextObjects::getGenericContextHeader;
  using TrailingGenericContextObjects::getFullGenericContextHeader;
  using TrailingGenericContextObjects::getGenericParams;

  /// 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;
  
  // 省略部分方法
};
  • TargetValueTypeDescriptor是它的父類,也就是說不同類型description都繼承于TargetValueTypeDescriptor
  • 在該結(jié)構(gòu)中發(fā)現(xiàn)兩個屬性
    • NumFields主要表示結(jié)構(gòu)體中屬性的個數(shù),如果只有一個字段偏移量則表示偏移量的長度
    • FieldOffsetVectorOffset表示這個結(jié)構(gòu)體元數(shù)據(jù)中存儲的屬性的字段偏移向量的偏移量,如果是0則表示沒有

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;
  }
};
  • 該類并沒有太多信息,我們繼續(xù)查看父類

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;
      
  bool isReflectable() const { return (bool)Fields; }

  // 省略部分方法
};
  • 我們可以得到該類繼承自TargetContextDescriptor
  • NameAccessFunctionPtr、Fields三個屬性
    • 其中name就是類型的名稱
    • AccessFunctionPtr是該類型元數(shù)據(jù)訪問函數(shù)的指針
    • Fields是一個指向該類型的字段描述符的指針

TargetContextDescriptor

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是描述上下文的標(biāo)志,包括它的種類和格式版本。
    • Parent是記錄父類上下文的,如果是頂級則為null

總結(jié)

  • 至此,我們就對結(jié)構(gòu)體的Description的層級結(jié)構(gòu)基本就理清楚了,現(xiàn)總結(jié)如下:

[圖片上傳失敗...(image-133e7-1684500526636)]

Mirror獲取數(shù)據(jù)

  • 到此我們對Description分析基本很透徹了,那么我們就回到最開始的初始化,看看Mirror都是怎樣從Description取出相應(yīng)的值的。

  • 在初始化方法中,主要干了一下幾件事:

    1. 獲取subjectType,如果傳入的有值就使用傳入的值,否則就通過_getNormalizedType函數(shù)去獲取
    2. 通過_getChildCount獲取childCount,然后獲取children,注意這里是懶加載的
    3. 針對父類SuperclassMirror處理
    4. 最后會獲取并解析顯示的樣式,并設(shè)置Mirror一些其他屬性。

type

let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
@_silgen_name("swift_reflectionMirror_normalizedType")
internal 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; });
}
  • 假設(shè)現(xiàn)在是結(jié)構(gòu)體類型,此時的impl就是個StructImpl類型,所以這里的typeStructImpl父類ReflectionMirrorImpl的屬性type

cout

let childCount = _getChildCount(subject, type: subjectType)
@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount<T>(_: T, type: Any.Type) -> Int
  • 實際調(diào)用swift_reflectionMirror_count方法
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();
  });
}
  • 仍然以結(jié)構(gòu)體為例,此時的implStructImpl,內(nèi)部的count()函數(shù):
intptr_t count() {
    if (!isReflectable()) {
        return 0;
    }

    auto *Struct = static_cast<const StructMetadata *>(type);
    return Struct->getDescription()->NumFields;
}
  • 這里的Struct就是個TargetStructMetadata類型
  • 通過getDescription()函數(shù)獲取到一個TargetStructDescriptor類型的Description
  • 然后取NumFields的值就是我們要的count。

屬性名和屬性值

let children = (0 ..< childCount).lazy.map({
    getChild(of: subject, type: subjectType, index: $0)
})
self.children = Children(children)
  • 通過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)
}
  • 內(nèi)部調(diào)用了_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
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);
  });
}
  • 這里我們可以看到是調(diào)用了implsubscript函數(shù),同樣以結(jié)構(gòu)體為例,我們在StructImpl中找到該函數(shù),源碼如下:
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);
}
  • 先通過childMetadata獲取到fieldInfo,其實這里就是獲取FieldType,也就是屬性名
  • 通過childOffset函數(shù)和index獲取到對于的偏移量,最后根據(jù)內(nèi)存偏移去到屬性值。
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;
}
  • 通過調(diào)用getFieldAt函數(shù)獲取屬性名稱
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))};
  };
  
  // 獲取元類型中的描述符,如果沒有返回null,否則返回Descriptor
  auto *baseDesc = base->getTypeContextDescriptor();
  if (!baseDesc)
    return failedToFindMetadata();
  
  // 通過調(diào)用get方法,內(nèi)部是base+offset,通過相對偏移拿到fields地址
  auto *fields = baseDesc->Fields.get();
  if (!fields)
    return failedToFindMetadata();
  
  // 從數(shù)組中通過下標(biāo)拿到對應(yīng)的字段
  auto &field = fields->getFields()[index];
  // 拿到字段名稱
  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};
}
  • 在該方法中,主要做了以下幾件事:
    1. 通過getTypeContextDescriptor獲取baseDesc,也就是我們說的Description
    2. 通過Fields.get()獲取到fields
    3. 通過getFields()[index]或取對應(yīng)的field
    4. 通過getFieldName()函數(shù)獲取到屬性名稱
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];
}
  • 調(diào)用TargetStructMetadata中的getFieldOffsets函數(shù)源碼如下:
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。

  • 獲取到偏移值后通過內(nèi)存偏移即可獲取到屬性值。

總結(jié)

至此我們對Mirror的原理基本探索完畢了,現(xiàn)在總結(jié)一下:

  1. Mirror通過初始化方法返回一個Mirror實例
  2. 這個實例對象根據(jù)傳入對象的類型去對應(yīng)的Metadata中找到Description
  3. Description可以獲取name也就是屬性的名稱
  4. 通過內(nèi)存偏移獲取到屬性值
  5. 還可以通過numFields獲取屬性的個數(shù)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容