Swift-進階 07:Mirror源碼解析

Swift 進階之路 文章匯總

本文主要是分析Mirror的底層實現,以及根據Mirror底層原理仿寫其結構的實現

Swift-進階 06:反射Mirror & 錯誤處理文章中,我們介紹了Mirror的使用,即JSON解析,對此我們有如下一些疑問:

  • 1、系統(tǒng)是如何通過Mirror獲取對應的屬性以及值的?

  • 2、Swift眾所周知是一門靜態(tài)語言,系統(tǒng)在底層到底做了什么,使swift具有了反射的特性呢?

下面我們來對Mirror的底層實現進行探索

Mirror底層源碼分析

反射的API主要是由兩部分實現的

  • 一部分是通過Swift實現,即ReflectionMirror.swift

  • 一部分是通過C++實現,即ReflectionMirror.mm

  • 兩者之間是通過暴露給swift的C++函數進行通信,即@_silgen_name修飾符會通知swift編譯器將這個swift函數映射成C++函數的符號

  • Mirror的源碼是在Mirror.swift文件中,路徑為swift->stdlib->public->core->Mirror.swift

swift 使用技巧

使用@_silgen_name關鍵字聲明的方法,實際調用是括號中的方法,例如swift_cjl_add實際調用的是c中的cjl_add

  • 通過C定義一個方法,在swift中使用
<!--1、定義c方法-->
//.h聲明
int cjl_add(int a, int b);
//.c中實現
int cjl_add(int a, int b){
    return a+b;
}

<!--2、橋接文件中引入頭文件-->
#import "test.h"

<!--3、swift使用-->
var value = cjl_add(10, 20)
print(value)

<!--4、打印結果-->
30
  • 可以將上述代碼中的第2步去掉刪除,采用@_silgen_name關鍵字
<!--1、swift中針對cjl_add方法的聲明-->
//通過@_silgen_name聲明
@_silgen_name("cjl_add")
func swift_cjl_add(_ a: Int32, _ b: Int32) -> Int32

<!--2、使用-->
var value = swift_cjl_add(20, 30)
print(value)

<!--3、打印結果-->
50

分析Mirror

  • Mirror.swift文件中找到Mirror,是一個結構體類型

    Mirror結構體

  • 查找其初始化方法public init(reflecting subject: Any)

public init(reflecting subject: Any) {
    //判斷 subject 是否符合 CustomReflectable動態(tài)類型
    if case let customized as CustomReflectable = subject {
      //如果符合,則由 customMirror 確定屬性
      self = customized.customMirror
    } else {
      //如果不符合,則由語言生成
      self = Mirror(internalReflecting: subject)
    }
}
  • 查找internalReflecting方法(路徑為swift->stdlib->public->core->ReflectionMirror.swift
extension Mirror {
  // Mirror的初始化器中檢索需要的信息
  /*
  - subject 將要被反射的值
  - subjectType 將要被反射的subject值的類型,通常是值的運行時類型
  - 
  */ 
  internal init(internalReflecting subject: Any,
              subjectType: Any.Type? = nil,
              customAncestor: Mirror? = nil)
  {
    //根據_getNormalizedType獲取傳入的subject的真正類型,其中type(of: subject)獲取的動態(tài)類型
    let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
    // 獲取屬性大小
    let childCount = _getChildCount(subject, type: subjectType)
    // 遍歷,將屬性存儲到字典中
    let children = (0 ..< childCount).lazy.map({
      // getChild函數時C++的_getChild 函數的簡單封裝,將標簽名字中包含的C字符串轉換為Swift字符串
      getChild(of: subject, type: subjectType, index: $0)
    })
    // 賦值給Mirror的屬性children
    self.children = Children(children)
    // 設置父類反射
    self._makeSuperclassMirror = {//按需求構建父類的Mirror的閉包
      // 獲取傳入對象的類
      guard let subjectClass = subjectType as? AnyClass,
            // 獲取父類
            let superclass = _getSuperclass(subjectClass) else {
        return nil//非類的類型、沒有父類的類的Mirror,會獲取到nil
      }
      
      // 調用者可以用一個可作為父類的Mirror直接返回Mirror實例來指定自定義的祖先的表現
      // 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
        }
      }
      // 給相同值返回一個將 superclass作為 subjectType的新的Mirror
      return Mirror(internalReflecting: subject,
                    subjectType: superclass,
                    customAncestor: customAncestor)
    }

    // 獲取并解析顯示的樣式,并設置Mirror的其他屬性
    let rawDisplayStyle = _getDisplayStyle(subject)
    switch UnicodeScalar(Int(rawDisplayStyle)) {
    case "c": self.displayStyle = .class
    case "e": self.displayStyle = .enum
    case "s": self.displayStyle = .struct
    case "t": self.displayStyle = .tuple
    case "\0": self.displayStyle = nil
    default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")
    }
    
    self.subjectType = subjectType
    self._defaultDescendantRepresentation = .generated
  }
  // 快速查找
  internal static func quickLookObject(_ subject: Any) -> _PlaygroundQuickLook? {
#if _runtime(_ObjC)
    let object = _getQuickLookObject(subject)
    return object.flatMap(_getClassPlaygroundQuickLook)
#else
    return nil
#endif
  }
}

??
<!--superclassMirror屬性的底層返回-->
public var superclassMirror: Mirror? {
    return _makeSuperclassMirror()
}
nternal let _makeSuperclassMirror: () -> Mirror?

1、通過_getNormalizedType獲取傳入的subject的真正類型
2、通過_getChildCount方法獲取類中的屬性個數
3、遍歷屬性,通過getChild方法(C++的_getChild 函數的簡單封裝)將標簽名字中包含的C字符串轉換為Swift字符串,并將屬性存儲到字典中,賦值給Mirror的屬性children
4、Mirror有一個屬性superclassMirror,會返回該類的父類,其底層是返回一個_makeSuperclassMirror屬性,用于保存父類的Mirror閉包。首先會通過subjectType獲取父類,然后按照需求構建父類的Mirror閉包,如果是非類的類型、沒有父類的類的Mirror,會獲取到nil。反之,則直接返回一個可作為父類的Mirror的實例對象。
5、獲取并解析顯示的樣式,并設置Mirror的其他屬性

  • 進入_getNormalizedType的實現,根據定義,最終會調用C++中的swift_reflectionMirror_normalizedType -> Call方法
@_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; });
}
??
/*
- passedValue 實際需要傳入的swift的值的指針
- T 該值的靜態(tài)類型
- passedType 被顯式傳入且會用在反射過程中的類型
- f 傳遞被查找到的會被調用的實現的對象引用
- 返回值:返回f參數調用時的返回值
*/ 
template<typename F>
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
          const F &f) -> decltype(f(nullptr))
{
  // 獲取type
  const Metadata *type;
  OpaqueValue *value;
  std::tie(type, value) = unwrapExistential(T, passedValue);
  // 判斷傳入type是否為空,如果不為空,則直接賦值給type
  if (passedType != nullptr) {
    type = passedType;
  }
  // 使用 ReflectionMirrorImpl 子類的實例去結束調用f,然后會調用這個實例上的方法去真正的工作完成
  auto call = [&](ReflectionMirrorImpl *impl) {
    // 返回的type是傳入非type
    impl->type = type;
    impl->value = value;
    auto result = f(impl);
    return result;
  };
  
  .....
  
  switch (type->getKind()) {
    case MetadataKind::Tuple: {//元組
        ......
    }
    case MetadataKind::Struct: {//結構體
       ......
    }
    case MetadataKind::Enum://枚舉
    case MetadataKind::Optional: {//可選
     ......
    }
    
    ......
}

??
<!--unwrapExistential實現-->
static std::tuple<const Metadata *, OpaqueValue *>
unwrapExistential(const Metadata *T, OpaqueValue *Value) {
  // If the value is an existential container, look through it to reflect the
  // contained value.如果該值是一個存在的容器,請查看它以反映包含的值。
  // TODO: Should look through existential metatypes too, but it doesn't
  // really matter yet since we don't have any special mirror behavior for
  // concrete metatypes yet.
  while (T->getKind() == MetadataKind::Existential) {
    auto *existential
      = static_cast<const ExistentialTypeMetadata *>(T);

    // Unwrap the existential container.打開存在容器
    T = existential->getDynamicType(Value);
    Value = existential->projectValue(Value);

    // Existential containers can end up nested in some cases due to generic
    // abstraction barriers.  Repeat in case we have a nested existential.
  }
  return std::make_tuple(T, Value);
}

??
<!--getDynamicType的實現-->
template<> const Metadata *
ExistentialTypeMetadata::getDynamicType(const OpaqueValue *container) const {
// 根據 獲取此存在類型使用的表示形式 判斷
  switch (getRepresentation()) {
  case ExistentialTypeRepresentation::Class: {
    auto classContainer =
      reinterpret_cast<const ClassExistentialContainer*>(container);
    void *obj = classContainer->Value;
    return swift_getObjectType(reinterpret_cast<HeapObject*>(obj));
  }
  case ExistentialTypeRepresentation::Opaque: {
    auto opaqueContainer =
      reinterpret_cast<const OpaqueExistentialContainer*>(container);
    return opaqueContainer->Type;
  }
  case ExistentialTypeRepresentation::Error: {
    const SwiftError *errorBox
      = *reinterpret_cast<const SwiftError * const *>(container);
    return errorBox->getType();
  }
  }

  swift_runtime_unreachable(
      "Unhandled ExistentialTypeRepresentation in switch.");
}

call中主要是一個大型switch聲明和一些額外的代碼去處理特殊的情況,主要是會ReflectionMirrorImpl子類實例去結束調用 f,然后會調用這個實例上的方法去讓真正的工作完成。

1、首先根據unwrapExistential獲取type類型,其依賴于metaData元數據
2、判斷傳入的passedType是否為空,如果不為空,則直接賦值給type
3、使用 ReflectionMirrorImpl子類的實例去結束調用f,然后會調用這個實例上的方法去真正的工作完成

swift-source源碼調試_getNormalizedType方法

  • 運行swift源碼,在Call函數的第一行加斷點
  • 在源碼終端依次輸入下面代碼
class CJLTeacher{var age = 18}
var t = CJLTeacher()
let mirror = Mirror(reflecting: t)

運行結果如下,會在call的調用處斷住


調試-1

其中參數的調試結果如下:

  • 其中valueMirror實例

  • typetype(of:)獲取的類型

  • T是自己傳入的類型

    調試-2

ReflectionMirrorImpl 反射基類

ReflectionMirrorImpl的種類主要有以下幾種:

  • TupleImpl 元組的反射

  • StructImpl 結構體的反射

  • EnumImpl 枚舉的反射

  • ClassImpl 類的反射

  • MetatypeImpl 元數據的反射

  • OpaqueImpl 不透明類型的反射

這里主要以Struct的反射為例

  • 首先查看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;
  //獲取枚舉的case名字
  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() {}
};
  • 進入StructImpl結構體的底層實現,需要注意一下幾點:
// Implementation for structs.
// ReflectionMirrorImpl 的子類 StructImpl 結構體反射
struct StructImpl : ReflectionMirrorImpl {
  bool isReflectable() {//是否支持反射
    const auto *Struct = static_cast<const StructMetadata *>(type);
    const auto &Description = Struct->getDescription();
    return Description->isReflectable();
  }
  // 用 s 的顯式樣式來表明這是一個結構體
  char displayStyle() {
    return 's';
  }
  
  intptr_t count() {
    if (!isReflectable()) {
      return 0;
    }
// 首先也是找到metadata,然后通過metadata找到desc,然后找到fields,即 NumFields 記錄屬性的count
    auto *Struct = static_cast<const StructMetadata *>(type);
    return Struct->getDescription()->NumFields;//屬性的count
  }

  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;
    //通過getFieldAt獲取屬性的名稱
    std::tie(name, fieldInfo) = getFieldAt(type, i);
    assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
    
    *outName = name.data();
    *outFreeFunc = nullptr;
    
    return fieldInfo;
  }
// subscript 用來獲取當前屬性的名稱和值
  AnyReturn subscript(intptr_t i, const char **outName,
                      void (**outFreeFunc)(const char *)) {
    // 獲取metaadata
    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);
  }
};

1、count方法中屬性個數的獲取,是通過metadata,然后找到其desc,然后找到NumFields獲取的,即NumFields 記錄屬性的count
2、subscript方法主要用來獲取當前屬性的名稱和值

  • 首先獲取metadata
  • 然后獲取屬性的偏移值fieldOffset
  • 通過首地址+偏移值,計算屬性存儲的指針

其他幾種的分析類似,這里不再作說明

仿寫Mirror結構

以上源碼說了這么多,是不是還是有點難以理解,下面我們通過仿寫底層的結構來幫助理解Mirror獲取屬性和值的原理

TargetStructMetadata結構體:struct的反射類

  • 從Struct的反射類StructImpl中可以知道,其type的類型是StructMetadata

    type類型

  • Metadata.h文件中搜索StructMetadata,其真正的類型是TargetStructMetadata

using StructMetadata = TargetStructMetadata<InProcess>;
  • TargetStructMetadata -> TargetValueMetadata結構體,而
    TargetValueMetadata繼承自TargetMetadata,在Swift-進階 02:類、對象、屬性文章中,我們已經知道,TargetMetadata中有一個屬性kind(相當于OC中的isa),而TargetValueMetadata除了擁有父類的kind,還有一個description,用于記錄元數據的描述
/// 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;

    ......
}

TargetValueTypeDescriptor類:記錄metadata信息

  • 由上面可知,Description的類型是TargetValueTypeDescriptor,其中有兩個屬性
    • NumFields 用于記錄屬性的count
    • FieldOffsetVectorOffset 用于記錄屬性在metadata中便宜向量的偏移量
template <typename Runtime>
class TargetStructDescriptor final
    : public TargetValueTypeDescriptor<Runtime>,
      public TrailingGenericContextObjects<TargetStructDescriptor<Runtime>,
                            TargetTypeGenericContextDescriptorHeader,
                            /*additional trailing objects*/
                            TargetForeignMetadataInitialization<Runtime>,
                            TargetSingletonMetadataInitialization<Runtime>> {
    ......
    
    /// The number of stored properties in the struct.
  /// If there is a field offset vector, this is its length.
  uint32_t NumFields;//記錄屬性的count
  /// 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;//記錄屬性在metadata中便宜向量的偏移量
  
    ......
}
  • 進入其繼承鏈TargetValueTypeDescriptor -> TargetTypeContextDescriptor類,其中有3個屬性
    • Name 用于記錄類型的名稱,標識當前的類型
    • AccessFunctionPtr 指向此類型的metadata訪問函數的指針
    • Fields 指向類型的descriptor的指針
template <typename Runtime>
class TargetTypeContextDescriptor
    : public TargetContextDescriptor<Runtime> {
public:
  /// The name of the type. 類型的名稱
  TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;

  /// A pointer to the metadata access function for this type.
  /// 指向此類型的元數據訪問函數的指針
  /// The function type here is a stand-in. You should use getAccessFunction()
  /// to wrap the function pointer in an accessor that uses the proper calling
  /// convention for a given number of arguments.
  TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
                              /*Nullable*/ true> AccessFunctionPtr;
  
  /// A pointer to the field descriptor for the type, if any.指向類型的字段描述符的指針
  TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
                              /*nullable*/ true> Fields;
   
    ......
}
  • 進入TargetContextDescriptor基類的定義,其中有兩個參數
    • Flags 用于表示描述context的標志,包含kind和version
    • Parent 用于表示父類的context,如果是在頂層,則表示沒有父類,則為NULL
/// Base class for all context descriptors.
template<typename Runtime>
struct TargetContextDescriptor {
  /// Flags describing the context, including its kind and format version.
  ContextDescriptorFlags Flags;
  
  /// The parent context, or null if this is a top-level context.
  TargetRelativeContextPointer<Runtime> Parent;
  
  ......
}

從上述的分析中我們可以得知,

  • 屬性的獲取時通過baseDesc->Fields.get();(在ReflectionMirror.mm文件中getFieldAt方法),即是通過Description中的Fields屬性獲取,所以還需要分析Fields的類型TargetRelativeDirectPointer,其內部的類型是FieldDescriptor

RelativeDirectPointerImpl類:存放offset偏移量

  • TargetRelativeDirectPointer的真正類型是RelativeDirectPointer -> RelativeDirectPointerImpl,RelativeDirectPointerImpl主要用于存放offset偏移量
    • 屬性RelativeOffset,用于表示屬性的相對偏移值,而不是直接存儲地址,如下所示

      相對偏移值

    • 其中PointerTy、ValueTy就是傳入的類型T、T的指針類型

template<typename T, bool Nullable, typename Offset>
class RelativeDirectPointerImpl {
private:
  /// The relative offset of the function's entry point from *this.
  Offset RelativeOffset;
  
    ......

public:
  using ValueTy = T;//是一個值
  using PointerTy = T*;//是一個指針
}
    //get方法 - 用于獲取屬性
  PointerTy get() const & {
    // Check for null.檢查是否為空
    if (Nullable && RelativeOffset == 0)
      return nullptr;
    
    // The value is addressed relative to `this`. 值是相對于“this”尋址的
    uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
    return reinterpret_cast<PointerTy>(absolute);
  }
    ......
}

??
<!--applyRelativeOffset的實現-->
template<typename BasePtrTy, typename Offset>
static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
  static_assert(std::is_integral<Offset>::value &&
                std::is_signed<Offset>::value,
                "offset type should be signed integer");
// 指針地址
  auto base = reinterpret_cast<uintptr_t>(basePtr);
  // We want to do wrapping arithmetic, but with a sign-extended
  // offset. To do this in C, we need to do signed promotion to get
  // the sign extension, but we need to perform arithmetic on unsigned values,
  // since signed overflow is undefined behavior.
  auto extendOffset = (uintptr_t)(intptr_t)offset;
  return base + extendOffset;//指針地址+存放的offset(偏移地址) -- 內存平移獲取值
}

FieldDescriptor類:存放屬性

進入FieldDescriptor類的定義,如下所示

class FieldDescriptor {
  const FieldRecord *getFieldRecordBuffer() const {
    return reinterpret_cast<const FieldRecord *>(this + 1);
  }

public:
  const RelativeDirectPointer<const char> MangledTypeName;
  const RelativeDirectPointer<const char> Superclass;

    ......

  const FieldDescriptorKind Kind;
  const uint16_t FieldRecordSize;
  const uint32_t NumFields;
  
    ......
  
  // 獲取所有屬性,每個屬性用FieldRecord封裝
   llvm::ArrayRef<FieldRecord> getFields() const {
    return {getFieldRecordBuffer(), NumFields};
  }
  
  ......
} 

FieldRecord類:封裝屬性

進入FieldRecord類,其定義如下

class FieldRecord {
  const FieldRecordFlags Flags;

public:
  const RelativeDirectPointer<const char> MangledTypeName;
  const RelativeDirectPointer<const char> FieldName;

上面主要分析了結構體通過Mirror獲取屬性和值涉及的類和結構體,其結構仿寫代碼如下

/// metadata元數據
struct StructMetadata {
//    (取自類 - TargetMetadata:kind)
    //(繼承關系:TargetStructMetadata -> TargetValueMetadata -> TargetMetadata)
    var kind: Int
//    (取自結構體 -  TargetValueMetadata:Description)
    var desc: UnsafeMutablePointer<StructMetadataDesc>
}

/// metada的描述信息
struct StructMetadataDesc {
//    (取自底層結構體 - TargetContextDescriptor:flags + parent)
    var flags: Int32
    var parent: Int32
//    (取自底層類 - TargetTypeContextDescriptor:name + AccessFunctionPtr + Fields)
    //type的名稱
    //相對指針位置的存儲
    var name: RelativeDirectPointer<CChar>
    //補充完整
    var AccessFunctionPtr: RelativeDirectPointer<UnsafeRawPointer>
    //是通過Fields的getFiledName獲取屬性名稱
    var Fields: RelativeDirectPointer<FieldDescriptor>
//    (取自底層類 - TargetClassDescriptor:NumFields + FieldOffsetVectorOffset)
    //屬性的count
    var NumFields: Int32
    var FieldOffsetVectorOffset: Int32
}

/// 屬性的描述信息
//(取自底層類 - FieldDescriptor)
struct FieldDescriptor {
    var MangledTypeName: RelativeDirectPointer<CChar>
    var Superclass: RelativeDirectPointer<CChar>
    var Kind: UInt16
    var FieldRecordSize: Int16
    var NumFields: Int32
    //每個屬性都是FieldRecord,記錄在這個結構體中
    var fields: FieldRecord//數組中是一個連續(xù)的存儲空間
}

/// 屬性封裝類
//(取自底層類 - FieldRecord)
struct FieldRecord{
    var Flags: Int32
    var MangledTypeName: RelativeDirectPointer<CChar>
    var FieldName: RelativeDirectPointer<CChar>
}


/// 記錄offset偏移值
struct RelativeDirectPointer<T>{
    var offset: Int32
    
    //模擬RelativeDirectPointerImpl類中的get方法 this+offset指針
    mutating func get() -> UnsafeMutablePointer<T>{
        let offset = self.offset
        return withUnsafePointer(to: &self) { p in
            /*
             獲得self,變?yōu)閞aw,然后+offset
             
             - UnsafeRawPointer(p) 表示this
             - advanced(by: numericCast(offset) 表示移動的步長,即offset
             - assumingMemoryBound(to: T.self) 表示假定類型是T,即自己制定的類型
             - UnsafeMutablePointer(mutating:) 表示返回的指針類型
            */
            return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))
        }
    }
}

其使用如下

  • 定義一個CJLTeacher類
struct CJLTeacher {
    var age = 18
    var name = "CJL"
}
  • 1、首先獲取指向metadata的指針
  • 2、然后獲取字符串的地址,例如name,并讀取內存值
/將t1綁定到StructMetadata(unsafeBitCast-按位強轉,非常危險,沒有任何校驗、沒有任何修飾)
//unsafeBitCast - 所有的內存按位轉換
//1、先獲取指向metadata的指針
let ptr = unsafeBitCast(CJLTeacher.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)

//2、然后獲取字符串的地址
/*
 ptr.pointee 表示StructMetadata
 ptr.pointee.desc.pointee 表示StructMetadataDesc
 ptr.pointee.desc.pointee.name 表示RelativeDirectPointer<T>
 */
let namePtr = ptr.pointee.desc.pointee.name.get()
print(String(cString: namePtr))
//讀取內存值
print(ptr.pointee.desc.pointee.NumFields)
  • 3、獲取首地址,通過指針移動來獲取訪問屬性的地址,例如輸出age屬性
//獲取首地址
let filedDescriptorPtr = ptr.pointee.desc.pointee.Fields.get()
//指針移動來獲取訪問屬性的地址
let recordPtr = withUnsafePointer(to: &filedDescriptorPtr.pointee.fields) {
    /*
     - UnsafeRawPointer + assumingMemoryBound -- 類型指針
     - advanced 類型指針只需要移動 下標即可
     */
    return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: FieldRecord.self).advanced(by: 0))
}
//輸出age屬性
print(String(cString: recordPtr.pointee.FieldName.get()))

如果將advanced中的0改成1,輸出name

打印結果

總結

所以綜上所述,Mirror反射干的事情:

  • 1、Mirror在實例對象的metadata中找到Descriptor

  • 2、在Descriptor

    • 找到name,獲取類型(相當于type名稱)
    • 找到numFields,獲取屬性個數
  • 3、找到FieldDescriptor中的fields,來找到對當前屬性的描述,然后通過指針移動,獲取其他屬性
    以上就是整個mirror在底層做的事情,如下所示,以struct為例的一個流程

    struct反射流程

【補充】

  • swift中的type(of:)、dump(t)就是基于Mirror的反射原理來實現的

  • swift中JSON解析的三方庫HandyJSON其原理就是Mirror反射的原理,本質就是利用metadata元數據中的descriptor,然后通過字段的訪問,做內存的賦值(后續(xù)會完整分析HandyJSON)

所以,針對我們開頭的兩個問題,可以通過上面的Mirror反射的原理來進行解釋
1、系統(tǒng)是如何通過Mirror獲取對應的屬性以及值的?
參考上述的Mirror原理總結

2、Swift眾所周知是一門靜態(tài)語言,系統(tǒng)在底層到底做了什么,使swift具有了反射的特性呢?
Swift 的反射機制是基于一個叫 Mirror 的 struct 來實現的。即為具體的 subject 創(chuàng)建一個 Mirror,然后就可以通過它查詢這個對象subject。簡單理解就是 Mirror通過meatadata,在其內部創(chuàng)建了一個結構,用于輸出metadata中的descriptor

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容