亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Swift中反射Mirror怎么用

發布時間:2021-09-22 09:45:44 來源:億速云 閱讀:168 作者:小新 欄目:web開發

小編給大家分享一下Swift中反射Mirror怎么用,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

前言

Mirror是Swift中的反射機制,對于C#和Java開發人員來說,應該很熟悉反射這個概念。反射就是可以動態的獲取類型以及成員信息,同時也可以在運行時動態的調用方法和屬性等。

對于iOS開發人員來說,入門時使用的Objective-C是很少強調反射概念的,因為OC的Runtime要比其他語言的反射強大的多。

1. Mirror 簡介

Mirror是Swift中的反射機制的實現,它的本質是一個結構體。其部分源碼(Swift 5.3.1)如下:

public struct Mirror {    /// A suggestion of how a mirror's subject is to be interpreted.   ///   /// Playgrounds and the debugger will show a representation similar   /// to the one used for instances of the kind indicated by the   /// `DisplayStyle` case name when the mirror is used for display.   public enum DisplayStyle {     case `struct`, `class`, `enum`, tuple, optional, collection     case dictionary, `set`   }          /// The static type of the subject being reflected.     ///     /// This type may differ from the subject's dynamic type when this mirror     /// is the `superclassMirror` of another mirror.     public let subjectType: Any.Type      /// A collection of `Child` elements describing the structure of the     /// reflected subject.     public let children: Children      /// A suggested display style for the reflected subject.     public let displayStyle: DisplayStyle?      /// A mirror of the subject's superclass, if one exists.     public var superclassMirror: Mirror? {       return _makeSuperclassMirror()     } }
  • subjectType:表示類型,被反射主體的類型

  • children:子元素集合

  • displayStyle:顯示類型,基本類型為 nil 枚舉值: struct, class, enum, tuple, optional,  collection, dictionary, set

  • superclassMirror:父類反射, 沒有父類為 nil

除了這些屬性還有一些初始化方法,我們最常用的就是初始化方法就是:

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

根據源碼我們還可以看到能夠使用customMirror,這個沒太研究,在源碼中可以看到很多CustomMirror的身影,感興趣的可以去研究研究。對于非customMirror的統一使用Mirror(internalReflecting:)進行初始化。

關于customMirror的補充,摘抄自 swiftGG Mirror 的工作原理。

Mirror允許類型用遵循 CustomReflectable  協議的方式提供一個自定義的表示方式。這給那些想表示得比內建形式更友好的類型提供一種有效的方法。比如 Array 類型遵守 CustomReflectable  協議并且暴露其中的元素為無標簽的 Children。Dictionary 使用這種方法暴露其中的鍵值對為帶標簽的 Children。

2. Mirror的簡單使用

? 2.1 基本使用

這里我們通過使用Mirror打印對象的屬性名稱和屬性值。

class Person {     var name: String = "xiaohei"     var age: Int = 18     var height = 1.85 }  var p = Person() var mirror = Mirror(reflecting: p.self)  print("對象類型:\(mirror.subjectType)") print("對象屬性個數:\(mirror.children.count)") print("對象的屬性及屬性值") for child in mirror.children {     print("\(child.label!)---\(child.value)") }

打印結果:

Swift中反射Mirror怎么用

我們可以看到,屬性名稱和值都已經正常打印。

? 2.2 將對象轉換為字典

首先我們來體驗一下將對象轉換為字典。

class Animal {     var name: String?     var color: String?     private var birthday: Date = Date(timeIntervalSince1970: 0) }   class Cat: Animal {     var master = "小黑"     var like: [String] = ["mouse", "fish"]          override init() {         super.init()         color = "黃色"     } }  func mapDic(mirror: Mirror) -> [String: Any] {     var dic: [String: Any] = [:]     for child in mirror.children {         // 如果沒有labe就會被拋棄         if let label = child.label {             let propertyMirror = Mirror(reflecting: child.value)             print(propertyMirror)             dic[label] = child.value         }     }     // 添加父類屬性     if let superMirror = mirror.superclassMirror {         let superDic = mapDic(mirror: superMirror)         for p in superDic {             dic[p.key] = p.value         }     }     return dic }   // Mirror使用 let cat = Cat() cat.name = "大橘為重" let mirror = Mirror(reflecting: cat) let mirrorDic = mapDic(mirror: mirror) print(mirrorDic)

打印結果:

Swift中反射Mirror怎么用

通過打印結果我們可以看到,對于一些基本類型,已經可選類型的數據都已經轉換為字典值,對于私有屬性也可以完成轉換。如果里面包含類則還需要進行遞歸處理。

? 2.3 轉 JSON

注:這里并沒有真正的轉換成json字符串,還是只轉換成了字典,重要在思想,如果需要轉換成json還需要很多優化,以及特殊字符串的考量。

其實提到反射我們想到最多的應該就是JSON了,這里我們利用Mirror的特性,將對象轉換成字典,對基本類型和類做了相應的處理,體會一下轉json的思路。

首先我們定義一個Person對象,代碼如下:

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

為了通用性,我們可以編寫一個協議,用來為所有類型提供轉換的方法,只需要遵守該協議就可以使用協議中的方法。

//可以轉換為 Json 的協議 protocol CustomJSONProtocol {     func toJSON() throws -> Any? }

協議的實現過程中會有些錯誤,我們也簡單的定義個枚舉,方便處理。為了更加詳細的描述錯誤信息,我們添加了錯誤描述和錯誤 code。

// 轉 json 時的錯誤類型 enum JSONMapError: Error{     case emptyKey     case notConformProtocol }  // 錯誤描述 extension JSONMapError: LocalizedError{     var errorDescription: String?{         switch self {         case .emptyKey:             return "key 為空"         case .notConformProtocol:            return "沒遵守協議"         }     } }  // errorcode extension JSONMapError: CustomNSError{     var errorCode: Int{         switch self {         case .emptyKey:             return 100         case .notConformProtocol:             return 101         }     } }

協議實現的代碼:

extension CustomJSONProtocol {     func toJSON() throws -> Any? {                  //創建 Mirror 類型         let mirror = Mirror(reflecting: self)         // 如果沒有屬性,比如一般類型String、Int等,直接返回自己         guard !mirror.children.isEmpty else { return self }                  var result: [String:Any] = [:]         // 遍歷         for children in mirror.children {             if let value = children.value as? CustomJSONProtocol{                 if let key = children.label {                     print(key)                     result[key] = try value.toJSON()                 } else {                    throw JSONMapError.emptyKey                 }             } else {                   throw JSONMapError.notConformProtocol             }         }                  return result     } }

將用到的類型都遵守協議

//將一般類型都遵從 CustomJSONProtocol 協議 extension Person: CustomJSONProtocol {} extension String: CustomJSONProtocol {} extension Int: CustomJSONProtocol {} extension Bool: CustomJSONProtocol {} extension Double: CustomJSONProtocol {} extension Float: CustomJSONProtocol {}      extension Address: CustomJSONProtocol {}  // 數組需要單獨處理,要不然就會報錯emptyKey extension Array: CustomJSONProtocol {     func toJSON() throws -> Any? {         return self     } }  //Optionai 需要特別對待,原因是如果直接返回,則會是 .Some: [...] extension Optional: CustomJSONProtocol {     func toJSON() throws -> Any? {         if let x = self {             if let value = x as? CustomJSONProtocol {                 return try value.toJSON()             }             throw JSONMapError.notConformProtocol         }         return nil     } }

最后我們打印一下:

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

打印結果:

Swift中反射Mirror怎么用

我們看到,對于some這空值,并沒有存儲到字典中,因為swift中的字典對于空值是刪除的意思。

如果想將其轉換成json還需修改"[]"為"{}",這個對于數組和對象還不好區分,另外對于json字符串內的一些value也有可能是應一串json還需要添加轉義字符等。

所以總的來說,思路是這樣的,要想真正的做成通用的轉json的方案還需要很多的優化,比如說,我們不可能將所有的基本類型都去遵守一個協議,這時候我們也可以考慮使用泛型去作為方法的參數。

3. Mirror 源碼解析

源碼版本Swift 5.3.1

在本章節我們將分析Mirror的部分源碼,查看其底層實現,最后通過Swift代碼使用內存重綁定的形式,仿寫一下Mirror,來更好的探索Mirror的原理,理解Mirror的思想。

我們知道Swift是一門靜態語言,那么在底層是如何實現的獲取對應的屬性值的呢?又或者說Swift的反射特性是如何實現的呢?下面我們通過對Mirror底層源碼的探索來尋找答案。

? 3.1 代碼結構

Mirror的實現是由一部分Swift代碼加上另一部分C++代碼。Swift代碼實現在ReflectionMirror.swift文件中,C++代碼實現在ReflectionMirror.mm文件中。Swift更適合用在實現更Swift的接口,但是在Swift中不能直接訪問C++的類。這里使用了@_silgen_name來實現Swift調用C++中的方法。舉個例子:

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

@_silgen_name修飾符會通知Swift編譯器將這個函數映射成swift_reflectionMirror_count符號,而不是Swift通常對應到的_getChildCount方法名修飾。需要注意的是,最前面的下劃線表示這個修飾是被保留在標準庫中的。在C++這邊,這個函數是這樣的。

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

SWIFT_CC(swift)會告訴編譯器這個函數使用的是Swift的調用約定,而不是C/C++的,SWIFT_RUNTIME_STDLIB_API標記這個函數,在Swift側的一部分接口中,而且它還有標記為extern  "C"的作用,從而避免C++的方法名修飾,并確保它在Swift側會有預期的符號。同時C++的參數會去特意匹配在Swift中聲明的函數調用。當Swift調用_getChildCount時,C++會用包含Swift值指針的value,包含類型參數type,包含類型響應的泛型的T的函數參數來調用此函數。

簡單的說就是使用@_silgen_name("xxx")修飾符修飾的Swift方法會調用括號中的xxx的符號,不管是C++的還是C的都可以。

Mirror的在Swift和C++之間的全部接口由以下函數組成:

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

? 3.2 初始化

在一開始我們簡單的介紹了Mirror的部分源碼,也由此知道Mirror(reflecting:)初始化方法可以接受任意值,返回一個提供該值子元素集合Children的相關信息的實例。

通過Mirror(reflecting:)源碼我們可以知道,其底層調用的是internalReflecting方法。在ReflectionMirror.swift文件的extension  Mirror中我們可以找到該方法。其源碼如下:

3.2.1 internalReflecting

internal init(internalReflecting subject: Any,              subjectType: Any.Type? = nil,              customAncestor: Mirror? = nil)  {    let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))        let childCount = _getChildCount(subject, type: subjectType)    let children = (0 ..< childCount).lazy.map({      getChild(of: subject, type: subjectType, index: $0)    })    self.children = Children(children)        self._makeSuperclassMirror = {      guard let subjectClass = subjectType as? AnyClass,            let superclass = _getSuperclass(subjectClass) else {        return nil      }            // Handle custom ancestors. If we've hit the custom ancestor's subject type,      // or descendants are suppressed, return it. Otherwise continue reflecting.      if let customAncestor = customAncestor {        if superclass == customAncestor.subjectType {          return customAncestor        }        if customAncestor._defaultDescendantRepresentation == .suppressed {          return customAncestor        }      }      return Mirror(internalReflecting: subject,                    subjectType: superclass,                    customAncestor: customAncestor)    }        let rawDisplayStyle = _getDisplayStyle(subject)    switch UnicodeScalar(Int(rawDisplayStyle)) {    case "c": self.displayStyle = .class    case "e": self.displayStyle = .enum    case "s": self.displayStyle = .struct    case "t": self.displayStyle = .tuple    case "\0": self.displayStyle = nil    default: preconditionFailure("Unknown raw display style '\(rawDisplayStyle)'")    }        self.subjectType = subjectType    self._defaultDescendantRepresentation = .generated  }

源碼分析:

  • 首先是獲取subjectType,如果傳入的有值就使用傳入的值,否則就通過_getNormalizedType函數去獲取

  • 接下來就是通過_getChildCount獲取childCount

  • 接下來是children,注意這里是懶加載的

  • 緊接著是SuperclassMirror,這里使用的是一個閉包的形式

  • 最后會獲取并解析顯示的樣式,并設置Mirror剩下的屬性。

3.2.2 _getNormalizedType

下面我們就來看看_getNormalizedType函數內部的實現。根據上面的分析我們知道實際調用是swift_reflectionMirror_normalizedType。在ReflectionMirror.mm文件中我們可以看到其源碼:

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

3.2.3 call函數

我們可以看到這里調用了一個call函數,最后返回的是impl的type。首先我們看看這call函數:

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

乍一看這個call函數代碼相對有點多,其實主要就是一個大型的switch聲明,和一些對特殊情況的處理,這里重要的就是,它會用一個ReflectionMirrorImpl的子類實例去結束調用f,然后會調用這個實例上的方法去讓真正的工作完成,這也就是為什么在swift_reflectionMirror_normalizedType函數中最后會return  impl->type;感興趣的可以通過源碼去調試一下,這里我也調試了,沒什么指的說的,這就就不寫調試過程了,下面我們就來看看ReflectionMirrorImpl。

3.2.4 ReflectionMirrorImpl

ReflectionMirrorImpl有以下6個子類:

  • TupleImpl 元組的反射

  • StructImpl 結構體的反射

  • EnumImpl 枚舉的反射

  • ClassImpl 類的反射

  • MetatypeImpl 元數據的反射

  • OpaqueImpl 不透明類型的反射

ReflectionMirrorImpl 源碼:

// Abstract base class for reflection implementations. struct ReflectionMirrorImpl {   const Metadata *type;   OpaqueValue *value;      virtual char displayStyle() = 0;   virtual intptr_t count() = 0;   virtual intptr_t childOffset(intptr_t index) = 0;   virtual const FieldType childMetadata(intptr_t index,                                         const char **outName,                                         void (**outFreeFunc)(const char *)) = 0;   virtual AnyReturn subscript(intptr_t index, const char **outName,                               void (**outFreeFunc)(const char *)) = 0;   virtual const char *enumCaseName() { return nullptr; }  #if SWIFT_OBJC_INTEROP   virtual id quickLookObject() { return nil; } #endif      // For class types, traverse through superclasses when providing field   // information. The base implementations call through to their local-only   // counterparts.   virtual intptr_t recursiveCount() {     return count();   }   virtual intptr_t recursiveChildOffset(intptr_t index) {     return childOffset(index);   }   virtual const FieldType recursiveChildMetadata(intptr_t index,                                                  const char **outName,                                                  void (**outFreeFunc)(const char *)) {     return childMetadata(index, outName, outFreeFunc);   }    virtual ~ReflectionMirrorImpl() {} };

ReflectionMirrorImpl源碼不多,但是我們可以看到type以及count等都在其中。下面我們以結構體為例,看看其子類的源碼。

3.2.5 結構體的反射

// Implementation for structs. struct StructImpl : ReflectionMirrorImpl {   bool isReflectable() {     const auto *Struct = static_cast<const StructMetadata *>(type);     const auto &Description = Struct->getDescription();     return Description->isReflectable();   }    char displayStyle() {     return 's';   }      intptr_t count() {     if (!isReflectable()) {       return 0;     }      auto *Struct = static_cast<const StructMetadata *>(type);     return Struct->getDescription()->NumFields;   }    intptr_t childOffset(intptr_t i) {     auto *Struct = static_cast<const StructMetadata *>(type);      if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)       swift::crash("Swift mirror subscript bounds check failure");      // Load the offset from its respective vector.     return Struct->getFieldOffsets()[i];   }    const FieldType childMetadata(intptr_t i, const char **outName,                                 void (**outFreeFunc)(const char *)) {     StringRef name;     FieldType fieldInfo;     std::tie(name, fieldInfo) = getFieldAt(type, i);     assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");          *outName = name.data();     *outFreeFunc = nullptr;          return fieldInfo;   }    AnyReturn subscript(intptr_t i, const char **outName,                       void (**outFreeFunc)(const char *)) {     auto fieldInfo = childMetadata(i, outName, outFreeFunc);      auto *bytes = reinterpret_cast<char*>(value);     auto fieldOffset = childOffset(i);     auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);      return copyFieldContents(fieldData, fieldInfo);   } };
  • 首先一個判斷是否支持反射的方法,最中是訪問的Description->isReflectable()

  • 這里使用&lsquo;s&rsquo;來顯式的表明這是一個結構體

  • 然后是獲取屬性個數

  • 緊接著是獲取每個屬性的偏移值

  • 然后獲取了FieldType內部還可以獲取到屬性的名稱。

  • 最后subscript方法可以獲取到屬性名稱和屬性偏移的指針,也就是屬性值。

? 3.3 Description

在此處我們看到很多關于Description的代碼,看來這個Description存儲著很多信息,在獲取Description的時候是從StructMetadata通過getDescription()方法獲取到。所以這些信息基本確定是從MetaData中獲取到的。StructMetadata是TargetStructMetadata的別名,我們以此為例。

3.3.1 TargetStructMetadata

在TargetStructMetadata我們可以看到如下代碼:

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

說明此處會返回一個TargetStructDescriptor類型的Description,但是在這里并沒有找到這個屬性,可能在父類中,我們可以看到TargetStructMetadata繼承自TargetValueMetadata。

3.3.2 TargetValueMetadata

在這里我們可以看到如下代碼:

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

這里我們便找到了:

  • Description屬性,它的類型是TargetValueTypeDescriptor,應該是TargetStructDescriptor的父類。

  • getDescription()方法,在TargetStructMetadata是重寫的這個方法

3.3.3 TargetStructDescriptor

跳轉到TargetStructDescriptor中后,我們可以看到:

  • TargetValueTypeDescriptor果然是它的父類

  • 在其源碼中我們還可以發現兩個屬性,分別是NumFields和FieldOffsetVectorOffset源碼如下:

/// The number of stored properties in the struct.   /// If there is a field offset vector, this is its length.   uint32_t NumFields;   /// The offset of the field offset vector for this struct's stored   /// properties in its metadata, if any. 0 means there is no field offset   /// vector.   uint32_t FieldOffsetVectorOffset;
  • 其中NumFields主要表示結構體中屬性的個數,如果只有一個字段偏移量則表示偏移量的長度

  • FieldOffsetVectorOffset表示這個結構體元數據中存儲的屬性的字段偏移向量的偏移量,如果是0則表示沒有

3.3.4 TargetValueTypeDescriptor

源碼如下,很少:

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

在這里我們并沒有找到太多有用的信息,我們繼續向父類尋找,其繼承自TargetTypeContextDescriptor

3.3.5 TargetTypeContextDescriptor

部分源碼:

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

我們可以看到:

該類繼承自TargetContextDescriptor

有Name、AccessFunctionPtr、Fields三個屬性

  • 其中name就是類型的名稱

  • AccessFunctionPtr是該類型元數據訪問函數的指針

  • Fields是一個指向該類型的字段描述符的指針

3.3.6 TargetContextDescriptor

接下來我們再看看TargetTypeContextDescriptor的父類中還有什么有用的信息。部分源碼如下:

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

這里我們可以看到:

這就是descriptors的基類

有兩個屬性,分別是Flags和Parent

  • 其中Flags是描述上下文的標志,包括它的種類和格式版本。

  • Parent是記錄父類上下文的,如果是頂級則為null

3.3.7 小結

至此我們對結構體Description的層級結構基本就理清楚了,現總結如下:

Swift中反射Mirror怎么用

從上圖我們可以看到,對于一個結構體的Description來說,繼承鏈上一共四個類,7個屬性。下面我們就對這些屬性作進一步的分析

? 3.4 Description中的屬性

3.4.1 Flags

Flags的類型是ContextDescriptorFlags,我們點擊跳轉進去,我們可以看到:

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

從以上的代碼中我們可以看到這個FLags實際是個uint32_t的值,按位存儲著kind、isGeneric、isUnique、version等信息。

3.4.2 Parent

Parent的類型是TargetRelativeContextPointer,我們看看TargetRelativeContextPointer,點擊跳轉過去:

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

我們可以看到TargetRelativeContextPointer是取自RelativeIndirectablePointer的別名,繼續點擊進行查看:

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

根據注釋我們就可以輕松的知道這個類的主要作用是存儲在內存中的對象的相對引用。這個意思在后面也有相關的解釋就是在內存中引用可以是直接的也可以是間接的,直接的就是存儲的絕對地址(也不一定,還有ASLR等),直接訪問這個地址就可以拿到對應的數據,而這里的相對引用就是間接的,這里面通過RelativeOffsetPlusIndirect屬性存儲相對的地址偏移量,在通過get()函數獲取,在get()函數中,會調用applyRelativeOffset函數,進行地址的偏移,applyRelativeOffset源碼:

/// Apply a relative offset to a base pointer. The offset is applied to the base /// pointer using sign-extended, wrapping arithmetic. template<typename BasePtrTy, typename Offset> static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {   static_assert(std::is_integral<Offset>::value &&                 std::is_signed<Offset>::value,                 "offset type should be signed integer");    auto base = reinterpret_cast<uintptr_t>(basePtr);   // We want to do wrapping arithmetic, but with a sign-extended   // offset. To do this in C, we need to do signed promotion to get   // the sign extension, but we need to perform arithmetic on unsigned values,   // since signed overflow is undefined behavior.   auto extendOffset = (uintptr_t)(intptr_t)offset;   return base + extendOffset; }

最后返回的時候我們可以看到base + extendOffset;基地址加上偏移的值,最后得到真實的地址。

3.4.2 name

name的類型是TargetRelativeDirectPointer

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

這里依舊是取別名,繼續跳轉到RelativeDirectPointer,這里有兩個選擇,我們選擇相對引用那個(通過注釋區別)。源碼如下:

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

在源碼中我們可以看到很多關于supper的東西,有兩處都是通過get()方法返回的,分別是PointerTy和ValueTy,下面我們就來到父類方法中看看。父類是RelativeDirectPointerImpl,其部分源碼如下:

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

這里同樣有一個Offset類型RelativeOffset,以及get()方法,同樣get()方法也會調用applyRelativeOffset函數進行地址的相加,關于applyRelativeOffset方法在介紹Parent的時候提到過。

這里面多了ValueTy和PointerTy,ValueTy是傳入泛型的值,PointerTy是其指針。

name中還有個const char,這里是直接用const char類型存儲的類型的名稱。

3.4.4 AccessFunctionPtr

AccessFunctionPtr的類型是TargetRelativeDirectPointer

跟name一樣的使用偏移指針TargetRelativeDirectPointer,只不過是const  char替換成了MetadataResponse(...),點擊MetadataResponse跳轉后我們可以看到如下代碼:

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

所以這里只是一個Metadata的指針。

3.4.5 Fields

Fields的類型是TargetRelativeDirectPointer

TargetRelativeDirectPointer就不多說了,這里看看FieldDescriptor點擊跳轉到其源碼處,部分源碼如下:

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

這里有5個屬性:

1. MangledTypeName

2. Superclass

3. kind

4. FieldRecordSize

5. NumFields

關于getFieldRecordBuffer函數的返回值FieldRecord源碼如下:

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

FieldRecord主要是封裝了一些屬性,用于存儲這些值。

3.4.6 NumFields

NumFields的類型是uint32_t這就沒什么好說的了,一個整形存儲屬性個數

3.4.7 FieldOffsetVectorOffset

FieldOffsetVectorOffset也是個uint32_t的整形,存儲偏移量。

? 3.5 Mirror取值

對于Description分析基本很透徹了,那么我們就回到最初的位置,看看Mirror都是怎樣從Description取出相應的值的。

3.5.1 type

首先我們看看type是怎么取的:

首先是調用swift_reflectionMirror_normalizedType函數

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

比如說這是個結構體,此時的impl就是個StructImpl類型,所以這里的type是StructImpl父類ReflectionMirrorImpl的屬性type。

3.5.2 count

關于count的獲取首先是調用swift_reflectionMirror_count函數

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

同樣還以結構體為例,此時的impl為StructImpl,內部的count()函數:

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

這里的Struct就是個TargetStructMetadata類型,通過getDescription()函數獲取到一個TargetStructDescriptor類型的Description,然后取NumFields的值就是我們要的count。

3.5.3 屬性名和屬性值

我們知道在Mirror中通過其初始化方法返回一個提供該值子元素的AnyCollection類型的children集合,Child是一個元組(label:  String?, value: Any),label是一個可選類型的屬性名,value是屬性值。

在分析internalReflecting函數的時候,我們說children是懶加載的,而加載的時候會調用getChild方法,getChild方法源碼入下:

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

在getChild方法中還會調用_getChild方法,源碼如下:

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

_getChild方法同樣是使用@_silgen_name修飾符最終調用的C++中的swift_reflectionMirror_subscript函數。

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

這里我們可以看到是調用了impl的subscript函數,同樣以結構體為例,我們在StructImpl中找到該函數,源碼如下:

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

通過subscript函數我們可以看到這里面還會調用childMetadata獲取到fieldInfo,其實這里就是獲取type,也就是屬性名,通過childOffset函數和index獲取到對于的偏移量,最后根據內存偏移去到屬性值。

childMetadata源碼:

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

這里面的關鍵點是調用調用getFieldAt函數獲取屬性名稱,

getFieldAt源碼:

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

我們可以看到在上面這個方法中:

  • 首先通過getTypeContextDescriptor獲取baseDesc,也就是我們說的Description

  • 然后通過Fields.get()獲取到fields

  • 接著通過getFields()[index]或取對應的field

  • 最后通過getFieldName()函數獲取到屬性名稱

  • getTypeContextDescriptor函數在struct TargetMetadata中,

  • 通過這個函數獲取到一個TargetStructDescriptor,它的父類的父類TargetTypeContextDescriptor中的Fields屬性

  • Fields屬性的類型TargetRelativeDirectPointer中有get方法

  • 實際中使用的FieldDescriptor類中getFieldRecordBuffer方法返回的FieldRecord中的getFieldName函數

getFields 源碼:

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

關于getFields我們可以看到這是一塊連續的空間,在begin和end中:

  • begin就是getFieldRecordBuffer

  • getFieldRecordBuffer就是Begin + NumFields

  • 所以這就是一塊連續內存的訪問

childOffset 源碼:

分析完了屬性名的獲取,我們來看看偏移量的獲取

intptr_t childOffset(intptr_t i) {     auto *Struct = static_cast<const StructMetadata *>(type);      if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)       swift::crash("Swift mirror subscript bounds check failure");      // Load the offset from its respective vector.     return Struct->getFieldOffsets()[i];   }

這里面是調用TargetStructMetadata中的getFieldOffsets函數源碼如下:

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

我們可以看到這里統一是通過獲取Description中的屬性,這里使用的屬性是FieldOffsetVectorOffset。

獲取到偏移值后通過內存偏移即可獲取到屬性值。

? 3.6 小結

至此我們對Mirror的原理基本探索完畢了,現在總結一下:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. Mirror通過初始化方法返回一會Mirror實例

  3. 這個實例對象根據傳入對象的類型去對應的Metadata中找到Description

  4. 在Description可以獲取name也就是屬性的名稱

  5. 通過內存偏移獲取到屬性值

  6. 還可以通過numFields獲取屬性的個數

下面通過該流程圖總結一下swift中的mirror對結構體進行反射的主要流程

Swift中反射Mirror怎么用

關于其他類型的反射也大同小異,還有元組、枚舉、類、元數據以及不透明類型的反射,當然也有不完全支持反射的類型,比如結構體就是不完全支持反射的類型,感興趣的可以繼續探索一下。

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

Swift中的json解析框架HandyJSON的主要原理與Mirror類似,本質上就是利用metadata中的Description,通過字段的訪問,做內存的賦值。

4. 仿寫 Mirror

為了加深對Mirror的理解,我們使用Swift語言仿寫一下。還是以結構體為例。

? 4.1 TargetStructMetadata

首先我們需要擁有一個結構體的元數據結構,這里我們命名為StructMetadata,里面有繼承的kind和Descriptor屬性,這里的Descriptor屬性是一個TargetStructDescriptor類型的指針。仿寫代碼如下:

struct StructMetadata{     var kind: Int     var Descriptor: UnsafeMutablePointer<StructDescriptor> }

? 4.2 TargetStructDescriptor

在4.1中我們用到的Descriptor屬性的內部結構現在也來實現一下。這個是Mirror中用到很多的屬性。對于結構體來說其內部有7個屬性

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. flag是個32位的整形,我們用Int32代替

  3. parent是記錄父類的,類型是TargetRelativeContextPointer

    ,這里也可以用Int32代替
  4. name記錄類型的,它的類型是TargetRelativeDirectPointer

    ,所以我們需要實現一個TargetRelativeDirectPointer
  5. AccessFunctionPtr與name類似,內部是個指針

  6. Fields也與name類似,內部是個FieldDescriptor

  7. NumFields使用Int32

  8. FieldOffsetVectorOffset也是用Int32

仿寫實現如下:

struct StructDescriptor {     let flags: Int32     let parent: Int32     var name: RelativePointer<CChar>     var AccessFunctionPtr: RelativePointer<UnsafeRawPointer>     var Fields: RelativePointer<FieldDescriptor>     var NumFields: Int32     var FieldOffsetVectorOffset: Int32 }

? 4.3 TargetRelativeDirectPointer

  • TargetRelativeDirectPointer是RelativeDirectPointer的別名,其內部有一個繼承的RelativeOffset屬性,是int32_t類型,我們可以用Int32代替。

  • 還有一個get方法。內部通過指針偏移獲取值

仿寫實現如下:

struct RelativePointer<T> {     var offset: Int32      mutating func get() -> UnsafeMutablePointer<T>{         let offset = self.offset          return withUnsafePointer(to: &self) { p in             return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))         }     } }

4.4 FieldDescriptor

FieldDescriptor在Mirror反射中有著很重要的作用,其內部有5個屬性:

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. MangledTypeName是RelativeDirectPointer

    類型,我們使用RelativePointer代替
  3. Superclass與MangledTypeName一樣

  4. kind是FieldDescriptorKind類型,實際是uint16_t,這里我們使用UInt16代替

  5. fieldRecordSize是uint16_t也使用使用UInt16代替

  6. numFields使用Int32代替

  7. fields,其實從屬性上看不到有這個,但是這里面有個getFieldRecordBuffer方法,通過this+1的方式一個一個的訪問屬性,所以這是一塊連續的內存空間,我們使用fields代替

仿寫代碼如下:

struct FieldDescriptor {     var MangledTypeName: RelativePointer<CChar>     var Superclass: RelativePointer<CChar>     var kind: UInt16     var fieldRecordSize: Int16     var numFields: Int32     var fields: FieldRecord //連續的存儲空間 }

? 4.5 FieldRecord

FieldRecord存儲著屬性的相關信息,其內部有三個屬性

  1. 鴻蒙官方戰略合作共建——HarmonyOS技術社區

  2. Flags是FieldRecordFlags類型實際是uint32_t,這里我們使用Int32代替

  3. MangledTypeName使用RelativePointer

    代替
  4. FieldName使用RelativePointer

    代替

仿寫帶如下:

struct FieldRecord {     var Flags: Int32     var MangledTypeName: RelativePointer<CChar>     var FieldName: RelativePointer<CChar> }

? 4.6 測試

下面我們使用內存綁定的計數訪問一個結構體

定義一個結構體:

struct Person {     var name: String = "xiaohei"     var age: Int = 18     var height = 1.85 }  var p = Person()

4.6.1 綁定結構體內存

使用unsafeBitCast按位強轉,將Person綁定到StructMetadata上,這個操作非常危險,沒有任何校驗和修飾

let ptr = unsafeBitCast(Person.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)

4.6.2 打印類型和屬性個數

下面我們就打印一下結構體的類型(也就是它的名稱)和其中屬性的個數:

let namePtr = ptr.pointee.Descriptor.pointee.name.get()  print(String(cString: namePtr)) print(ptr.pointee.Descriptor.pointee.NumFields)

打印結果:

Swift中反射Mirror怎么用

這里我們就可以看到結構體的名稱和其屬性個數的正確打印了。

4.6.3 打印屬性名稱

下面我們就來打印一下屬性的名稱,首先是獲取到FieldDescriptor的指針,然后通過內存偏移的方式訪問每一個FieldRecord,最后在訪問FieldRecord中的屬性名。代碼如下:

let fieldDescriptorPtr = ptr.pointee.Descriptor.pointee.Fields.get()  let recordPtr = withUnsafePointer(to: &fieldDescriptorPtr.pointee.fields) {     return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: FieldRecord.self).advanced(by: 2)) }  print(String(cString: recordPtr.pointee.FieldName.get()))

打印結果:

Swift中反射Mirror怎么用

此時我們就可以看到第三屬性height的打印,如果advanced(by: 0)則打印第一個屬性,以此類推。

Swift中反射Mirror怎么用

4.6.1 打印屬性值

下面我們訪問一下屬性值:

首先是獲取屬性偏移量的數組,也就是getFieldOffsets函數返回的值。根據源碼:

  • 首先獲取FieldOffsetVectorOffset的值

  • 然后在加上this也就是當前Metadata的指針

  • 這里我們將仿寫的StructMetadata的指針ptr重綁定為Int

  • 源碼中加上FieldOffsetVectorOffset,這里我們就移動FieldOffsetVectorOffset

  • 然后將上述移動后的綁定為一個Int32的指針

  • 最后使用UnsafeBufferPointer和屬性個數創建一個buffer數組指針

  • 接下來我們就可以從數組中取出每個屬性的偏移值

  • 然后取出結構體實例p的內存地址

  • 然后按照buffer數組中的偏移值進行偏移,重綁定為屬性的類型

  • 最后就可以打印出屬性值了

實現代碼:

var bufferPtr = UnsafeBufferPointer(start: UnsafeRawPointer(UnsafeRawPointer(ptr).assumingMemoryBound(to: Int.self).advanced(by: numericCast(ptr.pointee.Descriptor.pointee.FieldOffsetVectorOffset))).assumingMemoryBound(to: Int32.self), count: Int(ptr.pointee.Descriptor.pointee.NumFields))  var fieldOffset = bufferPtr[2]  var valuePtr = withUnsafeMutablePointer(to: &p) { $0 }  var bufferPtr1 = UnsafeRawPointer(UnsafeRawPointer(valuePtr).advanced(by: numericCast(bufferPtr[0]))).assumingMemoryBound(to: String.self) print(bufferPtr1.pointee)  var bufferPtr2 = UnsafeRawPointer(UnsafeRawPointer(valuePtr).advanced(by: numericCast(bufferPtr[1]))).assumingMemoryBound(to: Int.self) print(bufferPtr2.pointee)  var bufferPtr3 = UnsafeRawPointer(UnsafeRawPointer(valuePtr).advanced(by: numericCast(bufferPtr[2]))).assumingMemoryBound(to: Double.self) print(bufferPtr3.pointee)

打印結果:

Swift中反射Mirror怎么用

以上是“Swift中反射Mirror怎么用”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

永康市| 城市| 楚雄市| 萝北县| 资中县| 尼木县| 凤翔县| 融水| 仁怀市| 南川市| 周口市| 进贤县| 巴楚县| 南雄市| 马鞍山市| 岱山县| 乐业县| 阿克| 黄浦区| 富平县| 泾川县| 樟树市| 兴宁市| 南投县| 乌鲁木齐市| 青田县| 铅山县| 黄梅县| 胶州市| 苍梧县| 上杭县| 平潭县| 玉山县| 朔州市| 鲜城| 西安市| 郁南县| 临江市| 潞城市| 四会市| 米林县|