1. Mirror 简介
Mirror
是Swift
中的反射机制的完结,它的本质是一个结构体。其部分源码(Swift 5.3.1
)如下:
**
public struct Mirror {
/// A suggestion of how a mirror's subject is to be interpreted.
///
/// Playgrounds and the debugger will show a representation similar
/// to the one used for instances of the kind indicated by the
/// `DisplayStyle` case name when the mirror is used for display.
public enum DisplayStyle {
case `struct`, `class`, `enum`, tuple, optional, collection
case dictionary, `set`
}
/// The static type of the subject being reflected.
///
/// This type may differ from the subject's dynamic type when this mirror
/// is the `superclassMirror` of another mirror.
public let subjectType: Any.Type
/// A collection of `Child` elements describing the structure of the
/// reflected subject.
public let children: Children
/// A suggested display style for the reflected subject.
public let displayStyle: DisplayStyle?
/// A mirror of the subject's superclass, if one exists.
public var superclassMirror: Mirror? {
return _makeSuperclassMirror()
}
}
-
subjectType
:标明类型,被反射主体的类型 -
children
:子元素集合 -
displayStyle
:显现类型,根本类型为nil 枚举值:struct, class, enum, tuple, optional, collection, dictionary, set
-
superclassMirror
:父类反射, 没有父类为nil
除了这些特点还有一些初始化办法,咱们最常用的便是初始化办法便是:
**
/// Creates a mirror that reflects on the given instance.
///
/// If the dynamic type of `subject` conforms to `CustomReflectable`, the
/// resulting mirror is determined by its `customMirror` property.
/// Otherwise, the result is generated by the language.
///
/// If the dynamic type of `subject` has value semantics, subsequent
/// mutations of `subject` will not observable in `Mirror`. In general,
/// though, the observability of mutations is unspecified.
///
/// - Parameter subject: The instance for which to create a mirror.
public init(reflecting subject: Any) {
if case let customized as CustomReflectable = subject {
self = customized.customMirror
} else {
self = Mirror(internalReflecting: subject)
}
}
依据源码咱们还能够看到能够运用customMirror
,这个没太研究,在源码中能够看到许多CustomMirror
的身影,感兴趣的能够去研究研究。关于非customMirror
的统一运用Mirror(internalReflecting:)
进行初始化。
关于customMirror
的补充,摘抄自swiftGG Mirror 的作业原理。
Mirror
答应类型用遵循 CustomReflectable
协议的办法供给一个自界说的标明办法。这给那些想标明得比内建方式更友好的类型供给一种有用的办法。 比方 Array
类型恪守 CustomReflectable
协议而且露出其间的元素为无标签的 Children
。Dictionary
运用这种办法露出其间的键值对为带标签的 Children
。
2. Mirror的简略运用
2.1 根本运用
这儿咱们经过运用Mirror
打印目标的特点称号和特点值。
**
class Person {
var name: String = "xiaohei"
var age: Int = 18
var height = 1.85
}
var p = Person()
var mirror = Mirror(reflecting: p.self)
print("目标类型:(mirror.subjectType)")
print("目标特点个数:(mirror.children.count)")
print("目标的特点及特点值")
for child in mirror.children {
print("(child.label!)---(child.value)")
}
打印成果:
咱们能够看到,特点称号和值都现已正常打印。
2.2 将目标转化为字典
首要咱们来体验一下将目标转化为字典。
class Animal {
var name: String?
var color: String?
private var birthday: Date = Date(timeIntervalSince1970: 0)
}
class Cat: Animal {
var master = "小黑"
var like: [String] = ["mouse", "fish"]
override init() {
super.init()
color = "黄色"
}
}
func mapDic(mirror: Mirror) -> [String: Any] {
var dic: [String: Any] = [:]
for child in mirror.children {
// 假如没有labe就会被扔掉
if let label = child.label {
let propertyMirror = Mirror(reflecting: child.value)
print(propertyMirror)
dic[label] = child.value
}
}
// 增加父类特点
if let superMirror = mirror.superclassMirror {
let superDic = mapDic(mirror: superMirror)
for p in superDic {
dic[p.key] = p.value
}
}
return dic
}
// Mirror运用
let cat = Cat()
cat.name = "大橘为重"
let mirror = Mirror(reflecting: cat)
let mirrorDic = mapDic(mirror: mirror)
print(mirrorDic)
打印成果:
经过打印成果咱们能够看到,关于一些根本类型,现已可选类型的数据都现已转化为字典值,关于私有特点也能够完结转化。假如里边包括类则还需求进行递归处理。
2.3 转 JSON
注: 这儿并没有实在的转化成json字符串,仍是只转化成了字典,重要在思维,假如需求转化成json还需求许多优化,以及特殊字符串的考量。
其实说到反射咱们想到最多的应该便是JSON
了,这儿咱们运用Mirror
的特性,将目标转化成字典,对根本类型和类做了相应的处理,体会一下转json的思路。
首要咱们界说一个Person
目标,代码如下:
struct Person {
var name: String = "xiaohei"
var age: Int = 18
var isMale: Bool = true
var address: Address? = Address(street: "xizhimen North")
var height = 1.85
var like: Array = ["eat", "sleep", "play"]
var weight: Float = 75.0
var some: Int?
}
struct Address {
var street: String
}
// 创立一个Person目标
let p = Person()
为了通用性,咱们能够编写一个协议,用来为一切类型供给转化的办法,只需求恪守该协议就能够运用协议中的办法。
//能够转化为 Json 的协议
protocol CustomJSONProtocol {
func toJSON() throws -> Any?
}
协议的完结过程中会有些过错,咱们也简略的界说个枚举,便利处理。为了更加详细的描绘过错信息,咱们增加了过错描绘和过错code。
// 转 json 时的过错类型
enum JSONMapError: Error{
case emptyKey
case notConformProtocol
}
// 过错描绘
extension JSONMapError: LocalizedError{
var errorDescription: String?{
switch self {
case .emptyKey:
return "key 为空"
case .notConformProtocol:
return "没恪守协议"
}
}
}
// errorcode
extension JSONMapError: CustomNSError{
var errorCode: Int{
switch self {
case .emptyKey:
return 100
case .notConformProtocol:
return 101
}
}
}
协议完结的代码:
extension CustomJSONProtocol {
func toJSON() throws -> Any? {
//创立 Mirror 类型
let mirror = Mirror(reflecting: self)
// 假如没有特点,比方一般类型String、Int等,直接回来自己
guard !mirror.children.isEmpty else { return self }
var result: [String:Any] = [:]
// 遍历
for children in mirror.children {
if let value = children.value as? CustomJSONProtocol{
if let key = children.label {
print(key)
result[key] = try value.toJSON()
} else {
throw JSONMapError.emptyKey
}
} else {
throw JSONMapError.notConformProtocol
}
}
return result
}
}
将用到的类型都恪守协议
//将一般类型都遵照 CustomJSONProtocol 协议
extension Person: CustomJSONProtocol {}
extension String: CustomJSONProtocol {}
extension Int: CustomJSONProtocol {}
extension Bool: CustomJSONProtocol {}
extension Double: CustomJSONProtocol {}
extension Float: CustomJSONProtocol {}
extension Address: CustomJSONProtocol {}
// 数组需求独自处理,要不然就会报错emptyKey
extension Array: CustomJSONProtocol {
func toJSON() throws -> Any? {
return self
}
}
//Optionai 需求特别对待,原因是假如直接回来,则会是 .Some: [...]
extension Optional: CustomJSONProtocol {
func toJSON() throws -> Any? {
if let x = self {
if let value = x as? CustomJSONProtocol {
return try value.toJSON()
}
throw JSONMapError.notConformProtocol
}
return nil
}
}
终究咱们打印一下:
do {
print(try p.toJSON()!)
} catch {
print(error.localizedDescription)
print((error as? JSONMapError)?.errorCode)
}
打印成果:
咱们看到,关于some
这空值,并没有存储到字典中,由于swift
中的字典关于空值是删除的意思。
假如想将其转化成json
还需修改”[]”为”{}”,这个关于数组和目标还欠好区别,另外关于json
字符串内的一些value
也有可能是应一串json
还需求增加转义字符等。
所以总的来说,思路是这样的,要想实在的做成通用的转json
的方案还需求许多的优化,比方说,咱们不可能将一切的根本类型都去恪守一个协议,这时分咱们也能够考虑运用泛型去作为办法的参数。
3. Mirror 源码解析
源码版本Swift 5.3.1
在本章节咱们将剖析Mirror
的部分源码,查看其底层完结,终究经过Swift
代码运用内存重绑定的方式,仿写一下Mirror
,来更好的探究Mirror
的原理,了解Mirror
的思维。
咱们知道Swift
是一门静态语言,那么在底层是怎样完结的获取对应的特点值的呢?又或者说Swift
的反射特性是怎样完结的呢?下面咱们经过对Mirror
底层源码的探究来寻找答案。
3.1 代码结构
Mirror
的完结是由一部分Swift
代码加上另一部分C++
代码。Swift
代码完结在ReflectionMirror.swift
文件中,C++
代码完结在ReflectionMirror.mm
文件中。Swift
更适合用在完结更Swift
的接口,可是在Swift
中不能直接拜访C++
的类。这儿运用了@_silgen_name
来完结Swift
调用C++
中的办法。举个比如:
**
@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount<T>(_: T, type: Any.Type) -> Int
@_silgen_name
润饰符会通知Swift
编译器将这个函数映射成swift_reflectionMirror_count
符号,而不是Swift
通常对应到的_getChildCount
办法名润饰。需求留意的是,最前面的下划线标明这个润饰是被保留在规范库中的。在C++
这边,这个函数是这样的。
// func _getChildCount<T>(_: T, type: Any.Type) -> Int
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
intptr_t swift_reflectionMirror_count(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) {
return impl->count();
});
}
SWIFT_CC(swift)
会告知编译器这个函数运用的是Swift
的调用约好,而不是C/C++的,SWIFT_RUNTIME_STDLIB_API
标记这个函数,在Swift
侧的一部分接口中,而且它还有标记为extern "C"
的作用,然后避免C++
的办法名润饰,并确保它在Swift
侧会有预期的符号。一起C++
的参数会去特意匹配在Swift
中声明的函数调用。当Swift
调用_getChildCount
时,C++
会用包括Swift
值指针的value
,包括类型参数type
,包括类型呼应的泛型<T>
的T
的函数参数来调用此函数。
简略的说便是运用@_silgen_name("xxx")
润饰符润饰的Swift
办法会调用括号中的xxx
的符号,不管是C++
的仍是C
的都能够。
Mirror
的在Swift
和C++
之间的悉数接口由以下函数组成:
@_silgen_name("swift_isClassType")
internal func _isClassType(_: Any.Type) -> Bool
@_silgen_name("swift_getMetadataKind")
internal func _metadataKind(_: Any.Type) -> UInt
@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
@_silgen_name("swift_reflectionMirror_count")
internal func _getChildCount<T>(_: T, type: Any.Type) -> Int
@_silgen_name("swift_reflectionMirror_recursiveCount")
internal func _getRecursiveChildCount(_: Any.Type) -> Int
@_silgen_name("swift_reflectionMirror_recursiveChildMetadata")
internal func _getChildMetadata(
_: Any.Type,
index: Int,
outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any.Type
@_silgen_name("swift_reflectionMirror_recursiveChildOffset")
internal func _getChildOffset(
_: Any.Type,
index: Int
) -> Int
internal typealias NameFreeFunc = @convention(c) (UnsafePointer<CChar>?) -> Void
@_silgen_name("swift_reflectionMirror_subscript")
internal func _getChild<T>(
of: T,
type: Any.Type,
index: Int,
outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any
// Returns 'c' (class), 'e' (enum), 's' (struct), 't' (tuple), or '\0' (none)
@_silgen_name("swift_reflectionMirror_displayStyle")
internal func _getDisplayStyle<T>(_: T) -> CChar
internal func getChild<T>(of value: T, type: Any.Type, index: Int) -> (label: String?, value: Any) {
var nameC: UnsafePointer<CChar>? = nil
var freeFunc: NameFreeFunc? = nil
let value = _getChild(of: value, type: type, index: index, outName: &nameC, outFreeFunc: &freeFunc)
let name = nameC.flatMap({ String(validatingUTF8: $0) })
freeFunc?(nameC)
return (name, value)
}
#if _runtime(_ObjC)
@_silgen_name("swift_reflectionMirror_quickLookObject")
internal func _getQuickLookObject<T>(_: T) -> AnyObject?
@_silgen_name("_swift_stdlib_NSObject_isKindOfClass")
internal func _isImpl(_ object: AnyObject, kindOf: UnsafePointer<CChar>) -> Bool
3.2 初始化
在一开始咱们简略的介绍了Mirror
的部分源码,也由此知道Mirror(reflecting:)
初始化办法能够接受任意值,回来一个供给该值子元素集合Children
的相关信息的实例。
经过Mirror(reflecting:)
源码咱们能够知道,其底层调用的是internalReflecting
办法。在ReflectionMirror.swift
文件的extension Mirror
中咱们能够找到该办法。其源码如下:
3.2.1 internalReflecting
internal init(internalReflecting subject: Any,
subjectType: Any.Type? = nil,
customAncestor: Mirror? = nil)
{
let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
let childCount = _getChildCount(subject, type: subjectType)
let children = (0 ..< childCount).lazy.map({
getChild(of: subject, type: subjectType, index: $0)
})
self.children = Children(children)
self._makeSuperclassMirror = {
guard let subjectClass = subjectType as? AnyClass,
let superclass = _getSuperclass(subjectClass) else {
return nil
}
// Handle custom ancestors. If we've hit the custom ancestor's subject type,
// or descendants are suppressed, return it. Otherwise continue reflecting.
if let customAncestor = customAncestor {
if superclass == customAncestor.subjectType {
return customAncestor
}
if customAncestor._defaultDescendantRepresentation == .suppressed {
return customAncestor
}
}
return Mirror(internalReflecting: subject,
subjectType: superclass,
customAncestor: customAncestor)
}
let rawDisplayStyle = _getDisplayStyle(subject)
switch UnicodeScalar(Int(rawDisplayStyle)) {
case "c": self.displayStyle = .class
case "e": self.displayStyle = .enum
case "s": self.displayStyle = .struct
case "t": self.displayStyle = .tuple
case "\0": self.displayStyle = nil
default: preconditionFailure("Unknown raw display style '(rawDisplayStyle)'")
}
self.subjectType = subjectType
self._defaultDescendantRepresentation = .generated
}
源码剖析:
- 首要是获取
subjectType
,假如传入的有值就运用传入的值,不然就经过_getNormalizedType
函数去获取 - 接下来便是经过
_getChildCount
获取childCount
- 接下来是
children
,留意这儿是懒加载的 - 紧接着是
SuperclassMirror
,这儿运用的是一个闭包的方式 - 终究会获取并解析显现的样式,并设置
Mirror
剩下的特点。
3.2.2 _getNormalizedType
下面咱们就来看看_getNormalizedType
函数内部的完结。依据上面的剖析咱们知道实践调用是swift_reflectionMirror_normalizedType
。在ReflectionMirror.mm
文件中咱们能够看到其源码:
// func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}
3.2.3 call函数
咱们能够看到这儿调用了一个call
函数,终究回来的是impl
的type
。首要咱们看看这call
函数:
template<typename F>
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
const F &f) -> decltype(f(nullptr))
{
const Metadata *type;
OpaqueValue *value;
std::tie(type, value) = unwrapExistential(T, passedValue);
if (passedType != nullptr) {
type = passedType;
}
auto call = [&](ReflectionMirrorImpl *impl) {
impl->type = type;
impl->value = value;
auto result = f(impl);
return result;
};
auto callClass = [&] {
if (passedType == nullptr) {
// Get the runtime type of the object.
const void *obj = *reinterpret_cast<const void * const *>(value);
auto isa = _swift_getClass(obj);
// Look through artificial subclasses.
while (isa->isTypeMetadata() && isa->isArtificialSubclass()) {
isa = isa->Superclass;
}
passedType = isa;
}
#if SWIFT_OBJC_INTEROP
// If this is a pure ObjC class, reflect it using ObjC's runtime facilities.
// ForeignClass (e.g. CF classes) manifests as a NULL class object.
auto *classObject = passedType->getClassObject();
if (classObject == nullptr || !classObject->isTypeMetadata()) {
ObjCClassImpl impl;
return call(&impl);
}
#endif
// Otherwise, use the native Swift facilities.
ClassImpl impl;
return call(&impl);
};
switch (type->getKind()) {
case MetadataKind::Tuple: {
TupleImpl impl;
return call(&impl);
}
case MetadataKind::Struct: {
StructImpl impl;
return call(&impl);
}
case MetadataKind::Enum:
case MetadataKind::Optional: {
EnumImpl impl;
return call(&impl);
}
case MetadataKind::ObjCClassWrapper:
case MetadataKind::ForeignClass:
case MetadataKind::Class: {
return callClass();
}
case MetadataKind::Metatype:
case MetadataKind::ExistentialMetatype: {
MetatypeImpl impl;
return call(&impl);
}
case MetadataKind::Opaque: {
#if SWIFT_OBJC_INTEROP
// If this is the AnyObject type, use the dynamic type of the
// object reference.
if (type == &METADATA_SYM(BO).base) {
return callClass();
}
#endif
// If this is the Builtin.NativeObject type, and the heap object is a
// class instance, use the dynamic type of the object reference.
if (type == &METADATA_SYM(Bo).base) {
const HeapObject *obj
= *reinterpret_cast<const HeapObject * const*>(value);
if (obj->metadata->getKind() == MetadataKind::Class) {
return callClass();
}
}
LLVM_FALLTHROUGH;
}
/// TODO: Implement specialized mirror witnesses for all kinds.
default:
break;
// Types can't have these kinds.
case MetadataKind::HeapLocalVariable:
case MetadataKind::HeapGenericLocalVariable:
case MetadataKind::ErrorObject:
swift::crash("Swift mirror lookup failure");
}
// If we have an unknown kind of type, or a type without special handling,
// treat it as opaque.
OpaqueImpl impl;
return call(&impl);
}
乍一看这个call
函数代码相对有点多,其实首要便是一个大型的switch
声明,和一些对特殊情况的处理,这儿重要的便是,它会用一个ReflectionMirrorImpl
的子类实例去结束调用f
,然后会调用这个实例上的办法去让实在的作业完结,这也便是为什么在swift_reflectionMirror_normalizedType
函数中终究会return impl->type;
感兴趣的能够经过源码去调试一下,这儿我也调试了,没什么指的说的,这就就不写调试过程了,下面咱们就来看看ReflectionMirrorImpl
。
3.2.4 ReflectionMirrorImpl
ReflectionMirrorImpl
有以下6个子类:
- TupleImpl 元组的反射
- StructImpl 结构体的反射
- EnumImpl 枚举的反射
- ClassImpl 类的反射
- MetatypeImpl 元数据的反射
- OpaqueImpl 不透明类型的反射
ReflectionMirrorImpl 源码:
// Abstract base class for reflection implementations.
struct ReflectionMirrorImpl {
const Metadata *type;
OpaqueValue *value;
virtual char displayStyle() = 0;
virtual intptr_t count() = 0;
virtual intptr_t childOffset(intptr_t index) = 0;
virtual const FieldType childMetadata(intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *)) = 0;
virtual AnyReturn subscript(intptr_t index, const char **outName,
void (**outFreeFunc)(const char *)) = 0;
virtual const char *enumCaseName() { return nullptr; }
#if SWIFT_OBJC_INTEROP
virtual id quickLookObject() { return nil; }
#endif
// For class types, traverse through superclasses when providing field
// information. The base implementations call through to their local-only
// counterparts.
virtual intptr_t recursiveCount() {
return count();
}
virtual intptr_t recursiveChildOffset(intptr_t index) {
return childOffset(index);
}
virtual const FieldType recursiveChildMetadata(intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *))
{
return childMetadata(index, outName, outFreeFunc);
}
virtual ~ReflectionMirrorImpl() {}
};
ReflectionMirrorImpl
源码不多,可是咱们能够看到type
以及count
等都在其间。下面咱们以结构体为例,看看其子类的源码。
3.2.5 结构体的反射
// Implementation for structs.
struct StructImpl : ReflectionMirrorImpl {
bool isReflectable() {
const auto *Struct = static_cast<const StructMetadata *>(type);
const auto &Description = Struct->getDescription();
return Description->isReflectable();
}
char displayStyle() {
return 's';
}
intptr_t count() {
if (!isReflectable()) {
return 0;
}
auto *Struct = static_cast<const StructMetadata *>(type);
return Struct->getDescription()->NumFields;
}
intptr_t childOffset(intptr_t i) {
auto *Struct = static_cast<const StructMetadata *>(type);
if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
// Load the offset from its respective vector.
return Struct->getFieldOffsets()[i];
}
const FieldType childMetadata(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
*outName = name.data();
*outFreeFunc = nullptr;
return fieldInfo;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
auto fieldInfo = childMetadata(i, outName, outFreeFunc);
auto *bytes = reinterpret_cast<char*>(value);
auto fieldOffset = childOffset(i);
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
return copyFieldContents(fieldData, fieldInfo);
}
};
- 首要一个判断是否支撑反射的办法,最中是拜访的
Description->isReflectable()
- 这儿运用
‘s’
来显式的标明这是一个结构体 - 然后是获取特点个数
- 紧接着是获取每个特点的偏移值
- 然后获取了
FieldType
内部还能够获取到特点的称号。 - 终究
subscript
办法能够获取到特点称号和特点偏移的指针,也便是特点值。
3.3 Description
在此处咱们看到许多关于Description
的代码,看来这个Description
存储着许多信息,在获取Description
的时分是从StructMetadata
经过getDescription()
办法获取到。所以这些信息根本确定是从MetaData
中获取到的。StructMetadata
是TargetStructMetadata
的别号,咱们以此为例:
3.3.1 TargetStructMetadata
在TargetStructMetadata
咱们能够看到如下代码:
**
const TargetStructDescriptor<Runtime> *getDescription() const {
return llvm::cast<TargetStructDescriptor<Runtime>>(this->Description);
}
说明此处会回来一个TargetStructDescriptor
类型的Description
,可是在这儿并没有找到这个特点,可能在父类中,咱们能够看到TargetStructMetadata
承继自TargetValueMetadata
。
3.3.2 TargetValueMetadata
在这儿咱们能够看到如下代码:
/// An out-of-line description of the type.
TargetSignedPointer<Runtime, const TargetValueTypeDescriptor<Runtime> * __ptrauth_swift_type_descriptor> Description;
getDescription() const {
return Description;
}
这儿咱们便找到了:
-
Description
特点,它的类型是TargetValueTypeDescriptor
,应该是TargetStructDescriptor
的父类。 -
getDescription()
办法,在TargetStructMetadata
是重写的这个办法
3.3.3 TargetStructDescriptor
跳转到TargetStructDescriptor
中后,咱们能够看到:
-
TargetValueTypeDescriptor
果然是它的父类 - 在其源码中咱们还能够发现两个特点,分别是
NumFields
和FieldOffsetVectorOffset
源码如下:
/// The number of stored properties in the struct.
/// If there is a field offset vector, this is its length.
uint32_t NumFields;
/// The offset of the field offset vector for this struct's stored
/// properties in its metadata, if any. 0 means there is no field offset
/// vector.
uint32_t FieldOffsetVectorOffset;
- 其间
NumFields
首要标明结构体中特点的个数,假如只有一个字段偏移量则标明偏移量的长度 -
FieldOffsetVectorOffset
标明这个结构体元数据中存储的特点的字段偏移向量的偏移量,假如是0则标明没有
3.3.4 TargetValueTypeDescriptor
源码如下,很少:
template <typename Runtime>
class TargetValueTypeDescriptor
: public TargetTypeContextDescriptor<Runtime> {
public:
static bool classof(const TargetContextDescriptor<Runtime> *cd) {
return cd->getKind() == ContextDescriptorKind::Struct ||
cd->getKind() == ContextDescriptorKind::Enum;
}
};
在这儿咱们并没有找到太多有用的信息,咱们持续向父类寻找,其承继自TargetTypeContextDescriptor
3.3.5 TargetTypeContextDescriptor
部分源码:
template <typename Runtime>
class TargetTypeContextDescriptor
: public TargetContextDescriptor<Runtime> {
public:
/// The name of the type.
TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false> Name;
/// A pointer to the metadata access function for this type.
///
/// The function type here is a stand-in. You should use getAccessFunction()
/// to wrap the function pointer in an accessor that uses the proper calling
/// convention for a given number of arguments.
TargetRelativeDirectPointer<Runtime, MetadataResponse(...),
/*Nullable*/ true> AccessFunctionPtr;
/// A pointer to the field descriptor for the type, if any.
TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor,
/*nullable*/ true> Fields;
}
咱们能够看到:
-
该类承继自
TargetContextDescriptor
-
有
Name
、AccessFunctionPtr
、Fields
三个特点- 其间
name
便是类型的称号 -
AccessFunctionPtr
是该类型元数据拜访函数的指针 -
Fields
是一个指向该类型的字段描绘符的指针
- 其间
3.3.6 TargetContextDescriptor
接下来咱们再看看TargetTypeContextDescriptor
的父类中还有什么有用的信息。部分源码如下:
/// Base class for all context descriptors.
template<typename Runtime>
struct TargetContextDescriptor {
/// Flags describing the context, including its kind and format version.
ContextDescriptorFlags Flags;
/// The parent context, or null if this is a top-level context.
TargetRelativeContextPointer<Runtime> Parent;
}
这儿咱们能够看到:
-
这便是
descriptors
的基类 -
有两个特点,分别是
Flags
和Parent
- 其间
Flags
是描绘上下文的标志,包括它的种类和格式版本。 -
Parent
是记载父类上下文的,假如是尖端则为null
- 其间
3.3.7 小结
至此咱们对结构体Description
的层级结构根本就理清楚了,现总结如下:
从上图咱们能够看到,关于一个结构体的Description
来说,承继链上总共四个类,7个特点。下面咱们就对这些特点作进一步的剖析
3.4 Description中的特点
3.4.1 Flags
Flags
的类型是ContextDescriptorFlags
,咱们点击跳转进去,咱们能够看到:
/// Common flags stored in the first 32-bit word of any context descriptor.
struct ContextDescriptorFlags {
private:
uint32_t Value;
explicit constexpr ContextDescriptorFlags(uint32_t Value)
: Value(Value) {}
public:
constexpr ContextDescriptorFlags() : Value(0) {}
constexpr ContextDescriptorFlags(ContextDescriptorKind kind,
bool isGeneric,
bool isUnique,
uint8_t version,
uint16_t kindSpecificFlags)
: ContextDescriptorFlags(ContextDescriptorFlags()
.withKind(kind)
.withGeneric(isGeneric)
.withUnique(isUnique)
.withVersion(version)
.withKindSpecificFlags(kindSpecificFlags))
{}
......
}
从以上的代码中咱们能够看到这个FLags
实践是个uint32_t
的值,按位存储着kind
、isGeneric
、isUnique
、version
等信息。
3.4.2 Parent
Parent
的类型是TargetRelativeContextPointer<Runtime>
,咱们看看TargetRelativeContextPointer
,点击跳转过去:
using TargetRelativeContextPointer =
RelativeIndirectablePointer<const Context<Runtime>,
/*nullable*/ true, int32_t,
TargetSignedContextPointer<Runtime, Context>>;
咱们能够看到TargetRelativeContextPointer
是取自RelativeIndirectablePointer
的别号,持续点击进行查看:
/// A relative reference to an object stored in memory. The reference may be
/// direct or indirect, and uses the low bit of the (assumed at least
/// 2-byte-aligned) pointer to differentiate.
template<typename ValueTy, bool Nullable = false, typename Offset = int32_t, typename IndirectType = const ValueTy *>
class RelativeIndirectablePointer {
/// The relative offset of the pointer's memory from the `this` pointer.
/// If the low bit is clear, this is a direct reference; otherwise, it is
/// an indirect reference.
Offset RelativeOffsetPlusIndirect;
const ValueTy *get() const & {
static_assert(alignof(ValueTy) >= 2 && alignof(Offset) >= 2,
"alignment of value and offset must be at least 2 to "
"make room for indirectable flag");
// Check for null.
if (Nullable && RelativeOffsetPlusIndirect == 0)
return nullptr;
Offset offsetPlusIndirect = RelativeOffsetPlusIndirect;
uintptr_t address = detail::applyRelativeOffset(this,
offsetPlusIndirect & ~1);
// If the low bit is set, then this is an indirect address. Otherwise,
// it's direct.
if (offsetPlusIndirect & 1) {
return *reinterpret_cast<IndirectType const *>(address);
} else {
return reinterpret_cast<const ValueTy *>(address);
}
}
}
依据注释咱们就能够轻松的知道这个类的首要作用是存储在内存中的目标的相对引证。这个意思在后面也有相关的解释便是在内存中引证能够是直接的也能够是间接的,直接的便是存储的绝对地址(也不一定,还有ASLR
等),直接拜访这个地址就能够拿到对应的数据,而这儿的相对引证便是间接的,这儿边经过RelativeOffsetPlusIndirect
特点存储相对的地址偏移量,在经过get()
函数获取,在get()函数中,会调用applyRelativeOffset
函数,进行地址的偏移,applyRelativeOffset
源码:
**
/// Apply a relative offset to a base pointer. The offset is applied to the base
/// pointer using sign-extended, wrapping arithmetic.
template<typename BasePtrTy, typename Offset>
static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
static_assert(std::is_integral<Offset>::value &&
std::is_signed<Offset>::value,
"offset type should be signed integer");
auto base = reinterpret_cast<uintptr_t>(basePtr);
// We want to do wrapping arithmetic, but with a sign-extended
// offset. To do this in C, we need to do signed promotion to get
// the sign extension, but we need to perform arithmetic on unsigned values,
// since signed overflow is undefined behavior.
auto extendOffset = (uintptr_t)(intptr_t)offset;
return base + extendOffset;
}
终究回来的时分咱们能够看到base + extendOffset;
基地址加上偏移的值,终究得到实在的地址。
3.4.2 name
name
的类型是TargetRelativeDirectPointer<Runtime, const char, /*nullable*/ false>
,看着应该和Parent
差不多。咱们点击TargetRelativeDirectPointer
跳转到它的源码处:
template <typename Runtime, typename Pointee, bool Nullable = true>
using TargetRelativeDirectPointer
= typename Runtime::template RelativeDirectPointer<Pointee, Nullable>;
这儿依旧是取别号,持续跳转到RelativeDirectPointer
,这儿有两个挑选,咱们挑选相对引证那个(经过注释区别)。源码如下:
/// A direct relative reference to an object that is not a function pointer.
template <typename T, bool Nullable, typename Offset>
class RelativeDirectPointer<T, Nullable, Offset,
typename std::enable_if<!std::is_function<T>::value>::type>
: private RelativeDirectPointerImpl<T, Nullable, Offset>
{
using super = RelativeDirectPointerImpl<T, Nullable, Offset>;
public:
using super::get;
using super::super;
RelativeDirectPointer &operator=(T *absolute) & {
super::operator=(absolute);
return *this;
}
operator typename super::PointerTy() const & {
return this->get();
}
const typename super::ValueTy *operator->() const & {
return this->get();
}
using super::isNull;
};
在源码中咱们能够看到许多关于supper
的东西,有两处都是经过get()
办法回来的,分别是PointerTy
和ValueTy
,下面咱们就来到父类办法中看看。父类是RelativeDirectPointerImpl
,其部分源码如下:
/// A relative reference to a function, intended to reference private metadata
/// functions for the current executable or dynamic library image from
/// position-independent constant data.
template<typename T, bool Nullable, typename Offset>
class RelativeDirectPointerImpl {
private:
/// The relative offset of the function's entry point from *this.
Offset RelativeOffset;
public:
using ValueTy = T;
using PointerTy = T*;
PointerTy get() const & {
// Check for null.
if (Nullable && RelativeOffset == 0)
return nullptr;
// The value is addressed relative to `this`.
uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
return reinterpret_cast<PointerTy>(absolute);
}
}
这儿相同有一个Offset
类型RelativeOffset
,以及get()
办法,相同get()
办法也会调用applyRelativeOffset
函数进行地址的相加,关于applyRelativeOffset
办法在介绍Parent
的时分说到过。
这儿边多了ValueTy
和PointerTy
,ValueTy
是传入泛型的值,PointerTy
是其指针。
name
中还有个const char
,这儿是直接用const char
类型存储的类型的称号。
3.4.4 AccessFunctionPtr
AccessFunctionPtr
的类型是TargetRelativeDirectPointer<Runtime, MetadataResponse(...), /*Nullable*/ true>
跟name
相同的运用偏移指针TargetRelativeDirectPointer
,只不过是const char
替换成了MetadataResponse(...)
,点击MetadataResponse
跳转后咱们能够看到如下代码:
MetadataResponse() : Metadata(nullptr) {}
/// A metadata response that might not be dynamically complete.
explicit MetadataResponse(llvm::Value *metadata, llvm::Value *state,
MetadataState staticLowerBoundState)
: Metadata(metadata), DynamicState(state),
StaticState(staticLowerBoundState) {
assert(metadata && "must be valid");
}
所以这儿仅仅一个Metadata
的 指针。
3.4.5 Fields
Fields
的类型是TargetRelativeDirectPointer<Runtime, const reflection::FieldDescriptor, /*nullable*/ true>
TargetRelativeDirectPointer
就不多说了,这儿看看FieldDescriptor
点击跳转到其源码处,部分源码如下:
// Field descriptors contain a collection of field records for a single
// class, struct or enum declaration.
class FieldDescriptor {
const FieldRecord *getFieldRecordBuffer() const {
return reinterpret_cast<const FieldRecord *>(this + 1);
}
public:
const RelativeDirectPointer<const char> MangledTypeName;
const RelativeDirectPointer<const char> Superclass;
FieldDescriptor() = delete;
const FieldDescriptorKind Kind;
const uint16_t FieldRecordSize;
const uint32_t NumFields;
}
这儿有5个特点:
MangledTypeName
Superclass
kind
FieldRecordSize
NumFields
关于getFieldRecordBuffer
函数的回来值FieldRecord
源码如下:
class FieldRecord {
const FieldRecordFlags Flags;
public:
const RelativeDirectPointer<const char> MangledTypeName;
const RelativeDirectPointer<const char> FieldName;
.....
}
FieldRecord
首要是封装了一些特点,用于存储这些值。
3.4.6 NumFields
NumFields
的类型是uint32_t
这就没什么好说的了,一个整形存储特点个数
3.4.7 FieldOffsetVectorOffset
FieldOffsetVectorOffset
也是个uint32_t
的整形,存储偏移量。
3.5 Mirror取值
关于Description
剖析根本很透彻了,那么咱们就回到开始的位置,看看Mirror
都是怎样从Description
取出相应的值的。
3.5.1 type
首要咱们看看type
是怎样取的:
首要是调用swift_reflectionMirror_normalizedType
函数
**
// func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}
比方说这是个结构体,此刻的impl
便是个StructImpl
类型,所以这儿的type
是StructImpl
父类ReflectionMirrorImpl
的特点type
。
3.5.2 count
关于count
的获取首要是调用swift_reflectionMirror_count
函数
// func _getChildCount<T>(_: T, type: Any.Type) -> Int
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
intptr_t swift_reflectionMirror_count(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) {
return impl->count();
});
}
相同还以结构体为例,此刻的impl
为StructImpl
,内部的count()
函数:
intptr_t count() {
if (!isReflectable()) {
return 0;
}
auto *Struct = static_cast<const StructMetadata *>(type);
return Struct->getDescription()->NumFields;
}
这儿的Struct
便是个TargetStructMetadata
类型,经过getDescription()
函数获取到一个TargetStructDescriptor
类型的Description
,然后取NumFields
的值便是咱们要的count
。
3.5.3 特点名和特点值
咱们知道在Mirror
中经过其初始化办法回来一个供给该值子元素的AnyCollection<Child>
类型的children
集合,Child
是一个元组(label: String?, value: Any)
,label
是一个可选类型的特点名,value
是特点值。
在剖析internalReflecting
函数的时分,咱们说children
是懒加载的,而加载的时分会调用getChild
办法,getChild
办法源码入下:
internal func getChild<T>(of value: T, type: Any.Type, index: Int) -> (label: String?, value: Any) {
var nameC: UnsafePointer<CChar>? = nil
var freeFunc: NameFreeFunc? = nil
let value = _getChild(of: value, type: type, index: index, outName: &nameC, outFreeFunc: &freeFunc)
let name = nameC.flatMap({ String(validatingUTF8: $0) })
freeFunc?(nameC)
return (name, value)
}
在getChild
办法中还会调用_getChild
办法,源码如下:
@_silgen_name("swift_reflectionMirror_subscript")
internal func _getChild<T>(
of: T,
type: Any.Type,
index: Int,
outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
) -> Any
_getChild
办法相同是运用@_silgen_name
润饰符终究调用的C++
中的swift_reflectionMirror_subscript
函数。
// We intentionally use a non-POD return type with this entry point to give
// it an indirect return ABI for compatibility with Swift.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
// func _getChild<T>(
// of: T,
// type: Any.Type,
// index: Int,
// outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
// outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
// ) -> Any
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
AnyReturn swift_reflectionMirror_subscript(OpaqueValue *value, const Metadata *type,
intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *),
const Metadata *T) {
return call(value, T, type, [&](ReflectionMirrorImpl *impl) {
return impl->subscript(index, outName, outFreeFunc);
});
}
#pragma clang diagnostic pop
这儿咱们能够看到是调用了impl
的subscript
函数,相同以结构体为例,咱们在StructImpl
中找到该函数,源码如下:
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
auto fieldInfo = childMetadata(i, outName, outFreeFunc);
auto *bytes = reinterpret_cast<char*>(value);
auto fieldOffset = childOffset(i);
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
return copyFieldContents(fieldData, fieldInfo);
}
经过subscript
函数咱们能够看到这儿边还会调用childMetadata
获取到fieldInfo
,其实这儿便是获取type
,也便是特点名,经过childOffset
函数和index
获取到关于的偏移量,终究依据内存偏移去到特点值。
childMetadata源码:
const FieldType childMetadata(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
*outName = name.data();
*outFreeFunc = nullptr;
return fieldInfo;
}
这儿边的关键点是调用调用getFieldAt
函数获取特点称号,
getFieldAt源码:
static std::pair<StringRef /*name*/, FieldType /*fieldInfo*/>
getFieldAt(const Metadata *base, unsigned index) {
using namespace reflection;
// If we failed to find the field descriptor metadata for the type, fall
// back to returning an empty tuple as a standin.
auto failedToFindMetadata = [&]() -> std::pair<StringRef, FieldType> {
auto typeName = swift_getTypeName(base, /*qualified*/ true);
missing_reflection_metadata_warning(
"warning: the Swift runtime found no field metadata for "
"type '%*s' that claims to be reflectable. Its fields will show up as "
"'unknown' in Mirrors\n",
(int)typeName.length, typeName.data);
return {"unknown", FieldType(&METADATA_SYM(EMPTY_TUPLE_MANGLING))};
};
auto *baseDesc = base->getTypeContextDescriptor();
if (!baseDesc)
return failedToFindMetadata();
auto *fields = baseDesc->Fields.get();
if (!fields)
return failedToFindMetadata();
auto &field = fields->getFields()[index];
// Bounds are always valid as the offset is constant.
auto name = field.getFieldName();
// Enum cases don't always have types.
if (!field.hasMangledTypeName())
return {name, FieldType::untypedEnumCase(field.isIndirectCase())};
auto typeName = field.getMangledTypeName();
SubstGenericParametersFromMetadata substitutions(base);
auto typeInfo = swift_getTypeByMangledName(MetadataState::Complete,
typeName,
substitutions.getGenericArgs(),
[&substitutions](unsigned depth, unsigned index) {
return substitutions.getMetadata(depth, index);
},
[&substitutions](const Metadata *type, unsigned index) {
return substitutions.getWitnessTable(type, index);
});
// If demangling the type failed, pretend it's an empty type instead with
// a log message.
if (!typeInfo.getMetadata()) {
typeInfo = TypeInfo({&METADATA_SYM(EMPTY_TUPLE_MANGLING),
MetadataState::Complete}, {});
missing_reflection_metadata_warning(
"warning: the Swift runtime was unable to demangle the type "
"of field '%*s'. the mangled type name is '%*s'. this field will "
"show up as an empty tuple in Mirrors\n",
(int)name.size(), name.data(),
(int)typeName.size(), typeName.data());
}
auto fieldType = FieldType(typeInfo.getMetadata());
fieldType.setIndirect(field.isIndirectCase());
fieldType.setReferenceOwnership(typeInfo.getReferenceOwnership());
return {name, fieldType};
}
咱们能够看到在上面这个办法中:
- 首要经过
getTypeContextDescriptor
获取baseDesc
,也便是咱们说的Description
- 然后经过
Fields.get()
获取到fields
- 接着经过
getFields()[index]
或取对应的field
- 终究经过
getFieldName()
函数获取到特点称号 -
getTypeContextDescriptor
函数在struct TargetMetadata
中, - 经过这个函数获取到一个
TargetStructDescriptor
,它的父类的父类TargetTypeContextDescriptor
中的Fields
特点 -
Fields
特点的类型TargetRelativeDirectPointer
中有get
办法 - 实践中运用的
FieldDescriptor
类中getFieldRecordBuffer
办法回来的FieldRecord
中的getFieldName
函数
getFields 源码:
const_iterator begin() const {
auto Begin = getFieldRecordBuffer();
auto End = Begin + NumFields;
return const_iterator { Begin, End };
}
const_iterator end() const {
auto Begin = getFieldRecordBuffer();
auto End = Begin + NumFields;
return const_iterator { End, End };
}
llvm::ArrayRef<FieldRecord> getFields() const {
return {getFieldRecordBuffer(), NumFields};
}
关于getFields
咱们能够看到这是一块接连的空间,在begin
和end
中:
-
begin
便是getFieldRecordBuffer
-
getFieldRecordBuffer
便是Begin + NumFields
- 所以这便是一块接连内存的拜访
childOffset 源码:
剖析完了特点名的获取,咱们来看看偏移量的获取
intptr_t childOffset(intptr_t i) {
auto *Struct = static_cast<const StructMetadata *>(type);
if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
// Load the offset from its respective vector.
return Struct->getFieldOffsets()[i];
}
这儿边是调用TargetStructMetadata
中的getFieldOffsets
函数源码如下:
/// Get a pointer to the field offset vector, if present, or null.
const uint32_t *getFieldOffsets() const {
auto offset = getDescription()->FieldOffsetVectorOffset;
if (offset == 0)
return nullptr;
auto asWords = reinterpret_cast<const void * const*>(this);
return reinterpret_cast<const uint32_t *>(asWords + offset);
}
咱们能够看到这儿统一是经过获取Description
中的特点,这儿运用的特点是FieldOffsetVectorOffset
。
获取到偏移值后经过内存偏移即可获取到特点值。
3.6 小结
至此咱们对Mirror
的原理根本探究结束了,现在总结一下:
-
Mirror
经过初始化办法回来一会Mirror实例
- 这个实例目标依据传入目标的类型去对应的
Metadata
中找到Description
- 在
Description
能够获取name
也便是特点的称号 - 经过内存偏移获取到特点值
- 还能够经过
numFields
获取特点的个数
下面经过该流程图总结一下swift
中的mirror
对结构体进行反射的首要流程
关于其他类型的反射也迥然不同,还有元组、枚举、类、元数据以及不透明类型的反射,当然也有不完全支撑反射的类型,比方结构体便是不完全支撑反射的类型,感兴趣的能够持续探究一下。
-
swift
中的type(of:)
、dump(t)
便是基于Mirror
的反射原理来完结的 -
Swift
中的json
解析结构HandyJSON
的首要原理与Mirror
类似,本质上便是运用metadata
中的Description
,经过字段的拜访,做内存的赋值。