1、Mirror-反射机制
Mirror是Swift中的反射机制。所谓反射就是可以动态的获取类型、成员变量,在运行的时候可以调用方法、属性等行为的特性。在使用OC开发项目的过程中很少强调反射概念是因为OC的Runtime要比其他语言的反射强大的多,而Swift是类型安全的语言,不支持像OC那样直接操作,但是它的标准库仍然提供了反射机制来让我们访问成员变量
class XLMirror {
var age = 20
var name = "放得开"
}
var t = XLMirror()
let mirror = Mirror.init(reflecting: t)
for pro in mirror.children {
print("\(String(describing: pro.label)):\(pro.value)")
}
//代码的输出结果是:
//Optional("age"):20
//Optional("name"):放得开
Mirror在Swift源码中的本质是一个结构体:
subjectType: 表示类型,被反射主体的类型children: 子元素集合displayStyle:显示类型,基本类型为nil 枚举值:struct, class, enum, tuple, optional, collection, dictionary, set
这是Mirror最常用的初始化方法,接受一个Any类型的参数,if case的写法是用来判断当前的subject是否遵循了CustomReflectable协议,如果遵循了可以直接调用
public init(reflecting subject: Any) {
if case let customized as CustomReflectable = subject {
self = customized.customMirror
} else {
self = Mirror(internalReflecting: subject)
}
}
CustomReflectable协议的具体用法:
class XLMirror:CustomReflectable {
//遵循CustomReflectable协议
var age = 20
var name = "放得开"
//实现CustomReflectable协议的方法
var customMirror: Mirror {
let info = KeyValuePairs<String, Any>.init(dictionaryLiteral: ("age",age), ("name",name))
let mirror = Mirror.init(self, children: info, displayStyle: .class, ancestorRepresentation: .generated)
return mirror
}
}
var t = XLMirror()
最直观的区别就在于 LLDB输出的时候:
2、TargetStructMetadata的数据结构
2.1、还原StructMetadata数据结构
想要还原TargetStructMetadata,首先要了解TargetStructMetadata在源码中的数据结构,下面来源码中看一下:打开源码搜索TargetStructMetadata 可以定位到 Metadata.h 这个文件可以看到 TargetStructMetadata
是一个继承于TargetValueMetadata的 struct,而且TargetValueMetadata这个结构体提供了一个TargetValueTypeDescriptor类型的Description
继续向上寻找 可以看到 TargetValueMetadata 继承于 TargetMetadata,而 TargetMetadata提供了一个 StoredPointer类型的Kind
那么StructMetadata在swift中的代码就是这样的
struct TargetStructMetadata {
var kind: Int32
var Description:UnsafeRawPointer
}
2.2、还原TargetStructDescriptor数据结构
接下来看一下TargetValueTypeDescriptor这条线 TargetValueTypeDescriptor这个结构体继承自TargetValueTypeDescriptor而且本身提供了两个值 NumFields、FieldOffsetVectorOffset
继续向上寻找可以看到TargetValueTypeDescriptor继承自TargetValueTypeDescriptor,再找一层就能看到TargetValueTypeDescriptor继承自TargetTypeContextDescriptor,TargetTypeContextDescriptor这个类有TargetRelativeDirectPointer这个类型的三个值:Name、AccessFunctionPtr、Fields,其中Fields里存储的FieldDescriptor信息我们也需要还原一下
继续向上寻找会发现TargetTypeContextDescriptor继承自 TargetContextDescriptor的结构体,这个结构体提供了Flags、Parent这两个值
据此可以得到TargetStructDescriptor的数据结构
struct TargetStructDescriptor{
var Flags: Int32
var Parent: Int32
var Name: TargetRelativeDirectPointer<CChar>
var AccessFunctionPtr:TargetRelativeDirectPointer<UnsafeRawPointer>
var Fields: TargetRelativeDirectPointer<FieldDescriptor>
var NumFields: UInt32
var FieldOffsetVectorOffset: UInt32
}
2.3、还原FieldDescriptor数据结构
进入到FieldDescriptor可以看到有MangledTypeName、Superclass、Kind、FieldRecordSize、NumFields。FieldRecord这个类型的数据也需要还原
据此可知FieldDescriptor的数据结构为
struct FieldDescriptor{
var MangledTypeName: Int32
var Superclass: UnsafeRawPointer
var Kind: UInt16
var FieldRecordSize:UInt16 var NumFields: UnsafeRawPointer
var FieldRecord: Int32
}
2.4、还原FieldRecord数据结构
进入到FieldRecord类可以看到Flags、MangledTypeName、FieldName
据此可知FieldRecord数据结构
struct FieldRecord {
var Flags:Int32
var MangledTypeName:TargetRelativeDirectPointer<CChar>
var FieldName:TargetRelativeDirectPointer<CChar>
}
2.5、还原TargetRelativeDirectPointer
首先要搞清楚RelativeDirectPointer是什么,看一下源码
T是传进来的类型,Offset 就是 int32_t 的类型,在 Swift 中引⽤⼀个 Object 有两种情况:
- 当前 Object 的引⽤是⼀个 absolute 指针,就像我们的对象⼀样
-
当前指针存储的是相对引⽤,相对引⽤指的是当前引⽤的内存地址到当前对象的内存地址的距离
以上我们根据这个思路还原数据结构
typealias Offset = Int32 struct TargetRelativeDirectPointer{//相对地址信息 var offset: Offset
mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee>{ let offset = self.offset return withUnsafePointer(to: &self) { p in return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self)) } }}
最终的StructMetadata的数据结构应该是这样的
struct TargetRelativeDirectPointer<Pointee>{
var offset: Int32
mutating func getmeasureRelativeOffset() -> UnsafeMutablePointer<Pointee>{
let offset = self.offset
return withUnsafePointer(to: &self) { p in
return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: Pointee.self))
}
}
}
struct TargetStructMetadata {
var kind: Int32
var Description:UnsafeMutablePointer<TargetStructDescriptor>
}
struct TargetStructDescriptor{
var Flags: Int32
var Parent: Int32
var Name: TargetRelativeDirectPointer<CChar>
var AccessFunctionPtr:TargetRelativeDirectPointer<UnsafeRawPointer>
var Fields: TargetRelativeDirectPointer<FieldDescriptor>
var NumFields: UInt32
var FieldOffsetVectorOffset: Int32
func getFieldOffsets(_ metadata: UnsafeRawPointer) -> UnsafePointer<Int32>{
return UnsafeRawPointer(metadata.assumingMemoryBound(to: Int.self).advanced(by: numericCast(self.FieldOffsetVectorOffset))).assumingMemoryBound(to: Int32.self)
}
var genericArgumentOffset: Int {
return 2
}
}
struct FieldDescriptor{
var MangledTypeName: TargetRelativeDirectPointer<CChar>
var Superclass: TargetRelativeDirectPointer<CChar>
var Kind: UInt16
var FieldRecordSize:Int16
var NumFields: Int32
var FieldRecord: FiledRecordBuffer<FieldRecord>
}
struct FieldRecord {
var Flags:Int32
var MangledTypeName:TargetRelativeDirectPointer<CChar>
var FieldName:TargetRelativeDirectPointer<UInt8>
}
struct FiledRecordBuffer<Element>{
var element: Element
mutating func buffer(n: Int) -> UnsafeBufferPointer<Element> {
return withUnsafePointer(to: &self) {
let ptr = $0.withMemoryRebound(to: Element.self, capacity: 1) { start in
return start
}
return UnsafeBufferPointer(start: ptr, count: n)
}
}
mutating func index(of i: Int) -> UnsafeMutablePointer<Element> {
return withUnsafePointer(to: &self) {
return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: Element.self).advanced(by: i))
}
}
}
以上就是StructMetadata的swift数据结构,接下来验证码一下:
//首先创建一个结构体
struct XLCountry {
var name = "中国"
var english = "China"
var people = 140000
}
//然后按位存放在 TargetStructMetadata类型的指针
let ptr = unsafeBitCast(XLCountry.self as Any.Type, to: UnsafeMutablePointer<TargetStructMetadata>.self)
//拿到XLCountry的结构体的名字
let ptrName = ptr.pointee.Description.pointee.Name.getmeasureRelativeOffset()
//输出
print(String(cString: ptrName))//结果:XLStutend
print("当前类属性的个数: \(numFields)")//输出结果:3
再拿到XLCountry各属性的值以及属性的类型
let offsets = ptr.pointee.Description.pointee.getFieldOffsets(UnsafeRawPointer(ptr))
for i in 0 ..< numFields {
let structFields = ptr.pointee.Description.pointee.Fields.getmeasureRelativeOffset().pointee.FieldRecord.index(of: Int(i)).pointee.FieldName.getmeasureRelativeOffset()//获取XLCountry的属性的名字
print("---------start filed \(String(cString: structFields)) ---------")
let typeMangleName = ptr.pointee.Description.pointee.Fields.getmeasureRelativeOffset().pointee.FieldRecord.index(of: Int(i)).pointee.MangledTypeName.getmeasureRelativeOffset()//获取到属性的类型的名称(这个名称是混写后的)
let genericVector = UnsafeRawPointer(ptr).advanced(by: ptr.pointee.Description.pointee.genericArgumentOffset * MemoryLayout<UnsafeRawPointer>.size).assumingMemoryBound(to: Any.Type.self)
// const void * _Nullable swift_getTypeByMangledNameInContext(
// const char * _Nullable typeNameStart,
// int typeNameLength,
// const void * _Nullable context,
// const void * _Nullable const * _Nullable genericArgs);
let fieldType = swift_getTypeByMangledNameInContext(//C标准库里的方法,可以直接调用
typeMangleName,
256,
UnsafeRawPointer(ptr.pointee.Description),
UnsafeRawPointer(genericVector)?.assumingMemoryBound(to: Optional<UnsafeRawPointer>.self)
)
let type = unsafeBitCast(fieldType, to: Any.Type.self)
let value = customCast(type: type)
let instanceAddress = UnsafeRawPointer(withUnsafeMutablePointer(to: &country){$0})
var offset = offsets[Int(i)]
print("fieldType: \(type)")
let val = value.get(from: instanceAddress.advanced(by: Int(offset)))
print("fieldValue: \(val)")
print("---------end filed ---------")
}
输出结果
---------start filed name ---------
fieldType: String
fieldValue: 中国
---------end filed ---------
---------start filed english ---------
fieldType: String
fieldValue: China
---------end filed ---------
---------start filed people ---------
fieldType: Int
fieldValue: 140000
---------end filed ---------