您好,登錄后才能下訂單哦!
小編給大家分享一下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)大的多。
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。
這里我們通過使用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é)果:
我們可以看到,屬性名稱和值都已經(jīng)正常打印。
首先我們來體驗(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é)果:
通過打印結(jié)果我們可以看到,對(duì)于一些基本類型,已經(jīng)可選類型的數(shù)據(jù)都已經(jīng)轉(zhuǎn)換為字典值,對(duì)于私有屬性也可以完成轉(zhuǎn)換。如果里面包含類則還需要進(jìn)行遞歸處理。
注:這里并沒有真正的轉(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é)果:
我們看到,對(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ù)。
在本章節(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底層源碼的探索來尋找答案。
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)的泛型
簡(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
在一開始我們簡(jiǎn)單的介紹了Mirror的部分源碼,也由此知道Mirror(reflecting:)初始化方法可以接受任意值,返回一個(gè)提供該值子元素集合Children的相關(guān)信息的實(shí)例。
通過Mirror(reflecting:)源碼我們可以知道,其底層調(diào)用的是internalReflecting方法。在ReflectionMirror.swift文件的extension Mirror中我們可以找到該方法。其源碼如下:
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剩下的屬性。
下面我們就來看看_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; }); }
我們可以看到這里調(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。
ReflectionMirrorImpl有以下6個(gè)子類:
TupleImpl 元組的反射
StructImpl 結(jié)構(gòu)體的反射
EnumImpl 枚舉的反射
ClassImpl 類的反射
MetatypeImpl 元數(shù)據(jù)的反射
OpaqueImpl 不透明類型的反射
// 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)體為例,看看其子類的源碼。
// 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()
這里使用‘s’來顯式的表明這是一個(gè)結(jié)構(gòu)體
然后是獲取屬性個(gè)數(shù)
緊接著是獲取每個(gè)屬性的偏移值
然后獲取了FieldType內(nèi)部還可以獲取到屬性的名稱。
最后subscript方法可以獲取到屬性名稱和屬性偏移的指針,也就是屬性值。
在此處我們看到很多關(guān)于Description的代碼,看來這個(gè)Description存儲(chǔ)著很多信息,在獲取Description的時(shí)候是從StructMetadata通過getDescription()方法獲取到。所以這些信息基本確定是從MetaData中獲取到的。StructMetadata是TargetStructMetadata的別名,我們以此為例。
在TargetStructMetadata我們可以看到如下代碼:
const TargetStructDescriptor<Runtime> *getDescription() const { return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description); }
說明此處會(huì)返回一個(gè)TargetStructDescriptor類型的Description,但是在這里并沒有找到這個(gè)屬性,可能在父類中,我們可以看到TargetStructMetadata繼承自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è)方法
跳轉(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則表示沒有
源碼如下,很少:
template <typename Runtime> class TargetValueTypeDescriptor : public TargetTypeContextDescriptor<Runtime> { public: static bool classof(const TargetContextDescriptor<Runtime> *cd) { return cd->getKind() == ContextDescriptorKind::Struct || cd->getKind() == ContextDescriptorKind::Enum; } };
在這里我們并沒有找到太多有用的信息,我們繼續(xù)向父類尋找,其繼承自TargetTypeContextDescriptor
部分源碼:
template <typename Runtime> class TargetTypeContextDescriptor : public TargetContextDescriptor<Runtime> { public: /// The name of the type. TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name; /// A pointer to the metadata access function for this type. /// /// The function type here is a stand-in. You should use getAccessFunction() /// to wrap the function pointer in an accessor that uses the proper calling /// convention for a given number of arguments. TargetRelativeDirectPointer<Runtime, MetadataResponse(...), /*Nullable*/ true> AccessFunctionPtr; /// A pointer to the field descriptor for the type, if any. TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor, /*nullable*/ true> Fields; }
我們可以看到:
該類繼承自TargetContextDescriptor
有Name、AccessFunctionPtr、Fields三個(gè)屬性
其中name就是類型的名稱
AccessFunctionPtr是該類型元數(shù)據(jù)訪問函數(shù)的指針
Fields是一個(gè)指向該類型的字段描述符的指針
接下來我們?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
至此我們對(duì)結(jié)構(gòu)體Description的層級(jí)結(jié)構(gòu)基本就理清楚了,現(xiàn)總結(jié)如下:
從上圖我們可以看到,對(duì)于一個(gè)結(jié)構(gòu)體的Description來說,繼承鏈上一共四個(gè)類,7個(gè)屬性。下面我們就對(duì)這些屬性作進(jìn)一步的分析
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等信息。
Parent的類型是TargetRelativeContextPointer
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í)的地址。
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ǔ)的類型的名稱。
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的指針。
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ǔ)這些值。
NumFields的類型是uint32_t這就沒什么好說的了,一個(gè)整形存儲(chǔ)屬性個(gè)數(shù)
FieldOffsetVectorOffset也是個(gè)uint32_t的整形,存儲(chǔ)偏移量。
對(duì)于Description分析基本很透徹了,那么我們就回到最初的位置,看看Mirror都是怎樣從Description取出相應(yīng)的值的。
首先我們看看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。
關(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。
我們知道在Mirror中通過其初始化方法返回一個(gè)提供該值子元素的AnyCollection
在分析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)存偏移去到屬性值。
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ù)獲取屬性名稱,
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ù)
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)存的訪問
分析完了屬性名的獲取,我們來看看偏移量的獲取
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)存偏移即可獲取到屬性值。
至此我們對(duì)Mirror的原理基本探索完畢了,現(xiàn)在總結(jié)一下:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
Mirror通過初始化方法返回一會(huì)Mirror實(shí)例
這個(gè)實(shí)例對(duì)象根據(jù)傳入對(duì)象的類型去對(duì)應(yīng)的Metadata中找到Description
在Description可以獲取name也就是屬性的名稱
通過內(nèi)存偏移獲取到屬性值
還可以通過numFields獲取屬性的個(gè)數(shù)
下面通過該流程圖總結(jié)一下swift中的mirror對(duì)結(jié)構(gòu)體進(jìn)行反射的主要流程
關(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)存的賦值。
為了加深對(duì)Mirror的理解,我們使用Swift語言仿寫一下。還是以結(jié)構(gòu)體為例。
首先我們需要擁有一個(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.1中我們用到的Descriptor屬性的內(nèi)部結(jié)構(gòu)現(xiàn)在也來實(shí)現(xiàn)一下。這個(gè)是Mirror中用到很多的屬性。對(duì)于結(jié)構(gòu)體來說其內(nèi)部有7個(gè)屬性
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
flag是個(gè)32位的整形,我們用Int32代替
parent是記錄父類的,類型是TargetRelativeContextPointer
name記錄類型的,它的類型是TargetRelativeDirectPointer
AccessFunctionPtr與name類似,內(nèi)部是個(gè)指針
Fields也與name類似,內(nèi)部是個(gè)FieldDescriptor
NumFields使用Int32
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 }
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)) } } }
FieldDescriptor在Mirror反射中有著很重要的作用,其內(nèi)部有5個(gè)屬性:
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
MangledTypeName是RelativeDirectPointer
Superclass與MangledTypeName一樣
kind是FieldDescriptorKind類型,實(shí)際是uint16_t,這里我們使用UInt16代替
fieldRecordSize是uint16_t也使用使用UInt16代替
numFields使用Int32代替
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ǔ)空間 }
FieldRecord存儲(chǔ)著屬性的相關(guān)信息,其內(nèi)部有三個(gè)屬性
鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)
Flags是FieldRecordFlags類型實(shí)際是uint32_t,這里我們使用Int32代替
MangledTypeName使用RelativePointer
FieldName使用RelativePointer
仿寫帶如下:
struct FieldRecord { var Flags: Int32 var MangledTypeName: RelativePointer<CChar> var FieldName: RelativePointer<CChar> }
下面我們使用內(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()
使用unsafeBitCast按位強(qiáng)轉(zhuǎn),將Person綁定到StructMetadata上,這個(gè)操作非常危險(xiǎn),沒有任何校驗(yàn)和修飾
let ptr = unsafeBitCast(Person.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)
下面我們就打印一下結(jié)構(gòu)體的類型(也就是它的名稱)和其中屬性的個(gè)數(shù):
let namePtr = ptr.pointee.Descriptor.pointee.name.get() print(String(cString: namePtr)) print(ptr.pointee.Descriptor.pointee.NumFields)
打印結(jié)果:
這里我們就可以看到結(jié)構(gòu)體的名稱和其屬性個(gè)數(shù)的正確打印了。
下面我們就來打印一下屬性的名稱,首先是獲取到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é)果:
此時(shí)我們就可以看到第三屬性height的打印,如果advanced(by: 0)則打印第一個(gè)屬性,以此類推。
下面我們?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怎么用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(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)容。