溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Swift中反射Mirror怎么用

發(fā)布時(shí)間:2021-09-22 09:45:44 來源:億速云 閱讀:166 作者:小新 欄目:web開發(fā)

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

前言

Mirror是Swift中的反射機(jī)制,對(duì)于C#和Java開發(fā)人員來說,應(yīng)該很熟悉反射這個(gè)概念。反射就是可以動(dòng)態(tài)的獲取類型以及成員信息,同時(shí)也可以在運(yùn)行時(shí)動(dòng)態(tài)的調(diào)用方法和屬性等。

對(duì)于iOS開發(fā)人員來說,入門時(shí)使用的Objective-C是很少強(qiáng)調(diào)反射概念的,因?yàn)镺C的Runtime要比其他語言的反射強(qiáng)大的多。

1. Mirror 簡(jiǎn)介

Mirror是Swift中的反射機(jī)制的實(shí)現(xiàn),它的本質(zhì)是一個(gè)結(jié)構(gòu)體。其部分源碼(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)   } }

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

關(guān)于customMirror的補(bǔ)充,摘抄自 swiftGG Mirror 的工作原理。

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

2. Mirror的簡(jiǎn)單使用

? 2.1 基本使用

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

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

打印結(jié)果:

Swift中反射Mirror怎么用

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

? 2.2 將對(duì)象轉(zhuǎn)換為字典

首先我們來體驗(yàn)一下將對(duì)象轉(zhuǎn)換為字典。

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 {         // 如果沒有l(wèi)abe就會(huì)被拋棄         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)

打印結(jié)果:

Swift中反射Mirror怎么用

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

? 2.3 轉(zhuǎn) JSON

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

其實(shí)提到反射我們想到最多的應(yīng)該就是JSON了,這里我們利用Mirror的特性,將對(duì)象轉(zhuǎn)換成字典,對(duì)基本類型和類做了相應(yīng)的處理,體會(huì)一下轉(zhuǎn)json的思路。

首先我們定義一個(gè)Person對(duì)象,代碼如下:

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 }  // 創(chuàng)建一個(gè)Person對(duì)象 let p = Person()

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

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

協(xié)議的實(shí)現(xiàn)過程中會(huì)有些錯(cuò)誤,我們也簡(jiǎn)單的定義個(gè)枚舉,方便處理。為了更加詳細(xì)的描述錯(cuò)誤信息,我們添加了錯(cuò)誤描述和錯(cuò)誤 code。

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

協(xié)議實(shí)現(xiàn)的代碼:

extension CustomJSONProtocol {     func toJSON() throws -> Any? {                  //創(chuàng)建 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     } }

將用到的類型都遵守協(xié)議

//將一般類型都遵從 CustomJSONProtocol 協(xié)議 extension Person: CustomJSONProtocol {} extension String: CustomJSONProtocol {} extension Int: CustomJSONProtocol {} extension Bool: CustomJSONProtocol {} extension Double: CustomJSONProtocol {} extension Float: CustomJSONProtocol {}      extension Address: CustomJSONProtocol {}  // 數(shù)組需要單獨(dú)處理,要不然就會(huì)報(bào)錯(cuò)emptyKey extension Array: CustomJSONProtocol {     func toJSON() throws -> Any? {         return self     } }  //Optionai 需要特別對(duì)待,原因是如果直接返回,則會(huì)是 .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) }

打印結(jié)果:

Swift中反射Mirror怎么用

我們看到,對(duì)于some這空值,并沒有存儲(chǔ)到字典中,因?yàn)閟wift中的字典對(duì)于空值是刪除的意思。

如果想將其轉(zhuǎn)換成json還需修改"[]"為"{}",這個(gè)對(duì)于數(shù)組和對(duì)象還不好區(qū)分,另外對(duì)于json字符串內(nèi)的一些value也有可能是應(yīng)一串json還需要添加轉(zhuǎn)義字符等。

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

3. Mirror 源碼解析

源碼版本Swift 5.3.1

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

我們知道Swift是一門靜態(tài)語言,那么在底層是如何實(shí)現(xiàn)的獲取對(duì)應(yīng)的屬性值的呢?又或者說Swift的反射特性是如何實(shí)現(xiàn)的呢?下面我們通過對(duì)Mirror底層源碼的探索來尋找答案。

? 3.1 代碼結(jié)構(gòu)

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

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

@_silgen_name修飾符會(huì)通知Swift編譯器將這個(gè)函數(shù)映射成swift_reflectionMirror_count符號(hào),而不是Swift通常對(duì)應(yīng)到的_getChildCount方法名修飾。需要注意的是,最前面的下劃線表示這個(gè)修飾是被保留在標(biāo)準(zhǔn)庫中的。在C++這邊,這個(gè)函數(shù)是這樣的。

// 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)會(huì)告訴編譯器這個(gè)函數(shù)使用的是Swift的調(diào)用約定,而不是C/C++的,SWIFT_RUNTIME_STDLIB_API標(biāo)記這個(gè)函數(shù),在Swift側(cè)的一部分接口中,而且它還有標(biāo)記為extern  "C"的作用,從而避免C++的方法名修飾,并確保它在Swift側(cè)會(huì)有預(yù)期的符號(hào)。同時(shí)C++的參數(shù)會(huì)去特意匹配在Swift中聲明的函數(shù)調(diào)用。當(dāng)Swift調(diào)用_getChildCount時(shí),C++會(huì)用包含Swift值指針的value,包含類型參數(shù)type,包含類型響應(yīng)的泛型的T的函數(shù)參數(shù)來調(diào)用此函數(shù)。

簡(jiǎn)單的說就是使用@_silgen_name("xxx")修飾符修飾的Swift方法會(huì)調(diào)用括號(hào)中的xxx的符號(hào),不管是C++的還是C的都可以。

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

@_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 初始化

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

通過Mirror(reflecting:)源碼我們可以知道,其底層調(diào)用的是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函數(shù)去獲取

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

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

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

  • 最后會(huì)獲取并解析顯示的樣式,并設(shè)置Mirror剩下的屬性。

3.2.2 _getNormalizedType

下面我們就來看看_getNormalizedType函數(shù)內(nèi)部的實(shí)現(xiàn)。根據(jù)上面的分析我們知道實(shí)際調(diào)用是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函數(shù)

我們可以看到這里調(diào)用了一個(gè)call函數(shù),最后返回的是impl的type。首先我們看看這call函數(shù):

template<typename F> auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,           const F &f) -> decltype(f(nullptr)) {   const Metadata *type;   OpaqueValue *value;   std::tie(type, value) = unwrapExistential(T, passedValue);      if (passedType != nullptr) {     type = passedType;   }      auto call = [&](ReflectionMirrorImpl *impl) {     impl->type = type;     impl->value = value;     auto result = f(impl);     return result;   };      auto callClass = [&] {     if (passedType == nullptr) {       // Get the runtime type of the object.       const void *obj = *reinterpret_cast<const void * const *>(value);       auto isa = _swift_getClass(obj);        // Look through artificial subclasses.       while (isa->isTypeMetadata() && isa->isArtificialSubclass()) {         isa = isa->Superclass;       }       passedType = isa;     }    #if SWIFT_OBJC_INTEROP     // If this is a pure ObjC class, reflect it using ObjC's runtime facilities.     // ForeignClass (e.g. CF classes) manifests as a NULL class object.     auto *classObject = passedType->getClassObject();     if (classObject == nullptr || !classObject->isTypeMetadata()) {       ObjCClassImpl impl;       return call(&impl);     }   #endif      // Otherwise, use the native Swift facilities.     ClassImpl impl;     return call(&impl);   };      switch (type->getKind()) {     case MetadataKind::Tuple: {       TupleImpl impl;       return call(&impl);     }      case MetadataKind::Struct: {       StructImpl impl;       return call(&impl);     }           case MetadataKind::Enum:     case MetadataKind::Optional: {       EnumImpl impl;       return call(&impl);     }            case MetadataKind::ObjCClassWrapper:     case MetadataKind::ForeignClass:     case MetadataKind::Class: {       return callClass();     }      case MetadataKind::Metatype:     case MetadataKind::ExistentialMetatype: {       MetatypeImpl impl;       return call(&impl);     }      case MetadataKind::Opaque: { #if SWIFT_OBJC_INTEROP       // If this is the AnyObject type, use the dynamic type of the       // object reference.       if (type == &METADATA_SYM(BO).base) {         return callClass();       } #endif       // If this is the Builtin.NativeObject type, and the heap object is a       // class instance, use the dynamic type of the object reference.       if (type == &METADATA_SYM(Bo).base) {         const HeapObject *obj           = *reinterpret_cast<const HeapObject * const*>(value);         if (obj->metadata->getKind() == MetadataKind::Class) {           return callClass();         }       }       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); }

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

3.2.4 ReflectionMirrorImpl

ReflectionMirrorImpl有以下6個(gè)子類:

  • TupleImpl 元組的反射

  • StructImpl 結(jié)構(gòu)體的反射

  • EnumImpl 枚舉的反射

  • ClassImpl 類的反射

  • MetatypeImpl 元數(shù)據(jù)的反射

  • 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等都在其中。下面我們以結(jié)構(gòu)體為例,看看其子類的源碼。

3.2.5 結(jié)構(gòu)體的反射

// 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);   } };
  • 首先一個(gè)判斷是否支持反射的方法,最中是訪問的Description->isReflectable()

  • 這里使用&lsquo;s&rsquo;來顯式的表明這是一個(gè)結(jié)構(gòu)體

  • 然后是獲取屬性個(gè)數(shù)

  • 緊接著是獲取每個(gè)屬性的偏移值

  • 然后獲取了FieldType內(nèi)部還可以獲取到屬性的名稱。

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

? 3.3 Description

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

3.3.1 TargetStructMetadata

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

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

說明此處會(huì)返回一個(gè)TargetStructDescriptor類型的Description,但是在這里并沒有找到這個(gè)屬性,可能在父類中,我們可以看到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,應(yīng)該是TargetStructDescriptor的父類。

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

3.3.3 TargetStructDescriptor

跳轉(zhuǎn)到TargetStructDescriptor中后,我們可以看到:

  • TargetValueTypeDescriptor果然是它的父類

  • 在其源碼中我們還可以發(fā)現(xiàn)兩個(gè)屬性,分別是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主要表示結(jié)構(gòu)體中屬性的個(gè)數(shù),如果只有一個(gè)字段偏移量則表示偏移量的長(zhǎng)度

  • FieldOffsetVectorOffset表示這個(gè)結(jié)構(gòu)體元數(shù)據(jù)中存儲(chǔ)的屬性的字段偏移向量的偏移量,如果是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;   } };

在這里我們并沒有找到太多有用的信息,我們繼續(xù)向父類尋找,其繼承自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三個(gè)屬性

  • 其中name就是類型的名稱

  • AccessFunctionPtr是該類型元數(shù)據(jù)訪問函數(shù)的指針

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

3.3.6 TargetContextDescriptor

接下來我們?cè)倏纯碩argetTypeContextDescriptor的父類中還有什么有用的信息。部分源碼如下:

/// 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的基類

有兩個(gè)屬性,分別是Flags和Parent

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

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

3.3.7 小結(jié)

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

Swift中反射Mirror怎么用

從上圖我們可以看到,對(duì)于一個(gè)結(jié)構(gòu)體的Description來說,繼承鏈上一共四個(gè)類,7個(gè)屬性。下面我們就對(duì)這些屬性作進(jìn)一步的分析

? 3.4 Description中的屬性

3.4.1 Flags

Flags的類型是ContextDescriptorFlags,我們點(diǎn)擊跳轉(zhuǎn)進(jìn)去,我們可以看到:

/// 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))   {}      ...... }

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

3.4.2 Parent

Parent的類型是TargetRelativeContextPointer,我們看看TargetRelativeContextPointer,點(diǎn)擊跳轉(zhuǎn)過去:

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

我們可以看到TargetRelativeContextPointer是取自RelativeIndirectablePointer的別名,繼續(xù)點(diǎn)擊進(jìn)行查看:

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

根據(jù)注釋我們就可以輕松的知道這個(gè)類的主要作用是存儲(chǔ)在內(nèi)存中的對(duì)象的相對(duì)引用。這個(gè)意思在后面也有相關(guān)的解釋就是在內(nèi)存中引用可以是直接的也可以是間接的,直接的就是存儲(chǔ)的絕對(duì)地址(也不一定,還有ASLR等),直接訪問這個(gè)地址就可以拿到對(duì)應(yīng)的數(shù)據(jù),而這里的相對(duì)引用就是間接的,這里面通過RelativeOffsetPlusIndirect屬性存儲(chǔ)相對(duì)的地址偏移量,在通過get()函數(shù)獲取,在get()函數(shù)中,會(huì)調(diào)用applyRelativeOffset函數(shù),進(jìn)行地址的偏移,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; }

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

3.4.2 name

name的類型是TargetRelativeDirectPointer

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

這里依舊是取別名,繼續(xù)跳轉(zhuǎn)到RelativeDirectPointer,這里有兩個(gè)選擇,我們選擇相對(duì)引用那個(gè)(通過注釋區(qū)別)。源碼如下:

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

在源碼中我們可以看到很多關(guān)于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);   } }

這里同樣有一個(gè)Offset類型RelativeOffset,以及get()方法,同樣get()方法也會(huì)調(diào)用applyRelativeOffset函數(shù)進(jìn)行地址的相加,關(guān)于applyRelativeOffset方法在介紹Parent的時(shí)候提到過。

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

name中還有個(gè)const char,這里是直接用const char類型存儲(chǔ)的類型的名稱。

3.4.4 AccessFunctionPtr

AccessFunctionPtr的類型是TargetRelativeDirectPointer

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

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

所以這里只是一個(gè)Metadata的指針。

3.4.5 Fields

Fields的類型是TargetRelativeDirectPointer

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

// 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個(gè)屬性:

1. MangledTypeName

2. Superclass

3. kind

4. FieldRecordSize

5. NumFields

關(guān)于getFieldRecordBuffer函數(shù)的返回值FieldRecord源碼如下:

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

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

3.4.6 NumFields

NumFields的類型是uint32_t這就沒什么好說的了,一個(gè)整形存儲(chǔ)屬性個(gè)數(shù)

3.4.7 FieldOffsetVectorOffset

FieldOffsetVectorOffset也是個(gè)uint32_t的整形,存儲(chǔ)偏移量。

? 3.5 Mirror取值

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

3.5.1 type

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

首先是調(diào)用swift_reflectionMirror_normalizedType函數(shù)

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

比如說這是個(gè)結(jié)構(gòu)體,此時(shí)的impl就是個(gè)StructImpl類型,所以這里的type是StructImpl父類ReflectionMirrorImpl的屬性type。

3.5.2 count

關(guān)于count的獲取首先是調(diào)用swift_reflectionMirror_count函數(shù)

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

同樣還以結(jié)構(gòu)體為例,此時(shí)的impl為StructImpl,內(nèi)部的count()函數(shù):

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

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

3.5.3 屬性名和屬性值

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

在分析internalReflecting函數(shù)的時(shí)候,我們說children是懶加載的,而加載的時(shí)候會(huì)調(diào)用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方法中還會(huì)調(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

_getChild方法同樣是使用@_silgen_name修飾符最終調(diào)用的C++中的swift_reflectionMirror_subscript函數(shù)。

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

這里我們可以看到是調(diào)用了impl的subscript函數(shù),同樣以結(jié)構(gòu)體為例,我們?cè)赟tructImpl中找到該函數(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);   }

通過subscript函數(shù)我們可以看到這里面還會(huì)調(diào)用childMetadata獲取到fieldInfo,其實(shí)這里就是獲取type,也就是屬性名,通過childOffset函數(shù)和index獲取到對(duì)于的偏移量,最后根據(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;   }

這里面的關(guān)鍵點(diǎn)是調(diào)用調(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))};   };    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}; }

我們可以看到在上面這個(gè)方法中:

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

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

  • 接著通過getFields()[index]或取對(duì)應(yīng)的field

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

  • getTypeContextDescriptor函數(shù)在struct TargetMetadata中,

  • 通過這個(gè)函數(shù)獲取到一個(gè)TargetStructDescriptor,它的父類的父類TargetTypeContextDescriptor中的Fields屬性

  • Fields屬性的類型TargetRelativeDirectPointer中有g(shù)et方法

  • 實(shí)際中使用的FieldDescriptor類中g(shù)etFieldRecordBuffer方法返回的FieldRecord中的getFieldName函數(shù)

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

關(guān)于getFields我們可以看到這是一塊連續(xù)的空間,在begin和end中:

  • begin就是getFieldRecordBuffer

  • getFieldRecordBuffer就是Begin + NumFields

  • 所以這就是一塊連續(xù)內(nèi)存的訪問

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ù)源碼如下:

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

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

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

? 3.6 小結(jié)

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

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. Mirror通過初始化方法返回一會(huì)Mirror實(shí)例

  3. 這個(gè)實(shí)例對(duì)象根據(jù)傳入對(duì)象的類型去對(duì)應(yīng)的Metadata中找到Description

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

  5. 通過內(nèi)存偏移獲取到屬性值

  6. 還可以通過numFields獲取屬性的個(gè)數(shù)

下面通過該流程圖總結(jié)一下swift中的mirror對(duì)結(jié)構(gòu)體進(jìn)行反射的主要流程

Swift中反射Mirror怎么用

關(guān)于其他類型的反射也大同小異,還有元組、枚舉、類、元數(shù)據(jù)以及不透明類型的反射,當(dāng)然也有不完全支持反射的類型,比如結(jié)構(gòu)體就是不完全支持反射的類型,感興趣的可以繼續(xù)探索一下。

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

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

4. 仿寫 Mirror

為了加深對(duì)Mirror的理解,我們使用Swift語言仿寫一下。還是以結(jié)構(gòu)體為例。

? 4.1 TargetStructMetadata

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

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

? 4.2 TargetStructDescriptor

在4.1中我們用到的Descriptor屬性的內(nèi)部結(jié)構(gòu)現(xiàn)在也來實(shí)現(xiàn)一下。這個(gè)是Mirror中用到很多的屬性。對(duì)于結(jié)構(gòu)體來說其內(nèi)部有7個(gè)屬性

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

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

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

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

    ,所以我們需要實(shí)現(xiàn)一個(gè)TargetRelativeDirectPointer
  5. AccessFunctionPtr與name類似,內(nèi)部是個(gè)指針

  6. Fields也與name類似,內(nèi)部是個(gè)FieldDescriptor

  7. NumFields使用Int32

  8. FieldOffsetVectorOffset也是用Int32

仿寫實(shí)現(xiàn)如下:

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的別名,其內(nèi)部有一個(gè)繼承的RelativeOffset屬性,是int32_t類型,我們可以用Int32代替。

  • 還有一個(gè)get方法。內(nèi)部通過指針偏移獲取值

仿寫實(shí)現(xiàn)如下:

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反射中有著很重要的作用,其內(nèi)部有5個(gè)屬性:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. MangledTypeName是RelativeDirectPointer

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

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

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

  6. numFields使用Int32代替

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

仿寫代碼如下:

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

? 4.5 FieldRecord

FieldRecord存儲(chǔ)著屬性的相關(guān)信息,其內(nèi)部有三個(gè)屬性

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

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

  3. MangledTypeName使用RelativePointer

    代替
  4. FieldName使用RelativePointer

    代替

仿寫帶如下:

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

? 4.6 測(cè)試

下面我們使用內(nèi)存綁定的計(jì)數(shù)訪問一個(gè)結(jié)構(gòu)體

定義一個(gè)結(jié)構(gòu)體:

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

4.6.1 綁定結(jié)構(gòu)體內(nèi)存

使用unsafeBitCast按位強(qiáng)轉(zhuǎn),將Person綁定到StructMetadata上,這個(gè)操作非常危險(xiǎn),沒有任何校驗(yàn)和修飾

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

4.6.2 打印類型和屬性個(gè)數(shù)

下面我們就打印一下結(jié)構(gòu)體的類型(也就是它的名稱)和其中屬性的個(gè)數(shù):

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

打印結(jié)果:

Swift中反射Mirror怎么用

這里我們就可以看到結(jié)構(gòu)體的名稱和其屬性個(gè)數(shù)的正確打印了。

4.6.3 打印屬性名稱

下面我們就來打印一下屬性的名稱,首先是獲取到FieldDescriptor的指針,然后通過內(nèi)存偏移的方式訪問每一個(gè)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()))

打印結(jié)果:

Swift中反射Mirror怎么用

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

Swift中反射Mirror怎么用

4.6.1 打印屬性值

下面我們?cè)L問一下屬性值:

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

  • 首先獲取FieldOffsetVectorOffset的值

  • 然后在加上this也就是當(dāng)前Metadata的指針

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

  • 源碼中加上FieldOffsetVectorOffset,這里我們就移動(dòng)FieldOffsetVectorOffset

  • 然后將上述移動(dòng)后的綁定為一個(gè)Int32的指針

  • 最后使用UnsafeBufferPointer和屬性個(gè)數(shù)創(chuàng)建一個(gè)buffer數(shù)組指針

  • 接下來我們就可以從數(shù)組中取出每個(gè)屬性的偏移值

  • 然后取出結(jié)構(gòu)體實(shí)例p的內(nèi)存地址

  • 然后按照buffer數(shù)組中的偏移值進(jìn)行偏移,重綁定為屬性的類型

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

實(shí)現(xiàn)代碼:

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)

打印結(jié)果:

Swift中反射Mirror怎么用

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

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI