Swift.Mirror底层源码解析

768 阅读1分钟

查看swift源码分析mirror是怎样通过反射来获取到属性,个数,值 搜索mirror.swift在右边找到了初始化方法,又一个if语句,第一个是自定义的初始化,第二个是系统的初始化,主要看第二个

mirror获取类型

从上图中可看出查找struct类型的整个过程,仿写一个

属性个数

属性名称

//已知StructMetadata中有两个属性,
//kind是从他的基类TargetMetadata继承过来的
//description是他本身就有的描述信息属性
struct StructMetadata {
    var kind: Int
    var description: UnsafeMutablePointer<StructMetadataDesc>
}

//描述信息属性中又有三个属性
//flags和parent是从父类继承的
//name是类名属性
struct StructMetadataDesc {
    var flags: UInt32     //从TargetContextDescriptor继承所得
    var parent: UInt32    //从TargetContextDescriptor继承所得
    var name: RelativeDirectPointer<CChar>       //TargetTypeContextDescriptor的属性
    var accessFunctionPtr: RelativeDirectPointer<UnsafeRawPointer>    //TargetTypeContextDescriptor的属性
    var fields: RelativeDirectPointer<FieldDescriptor>         //TargetTypeContextDescriptor的属性
    var numFields: UInt32  // 属性个数        //TargetStructDescriptor的属性
}

struct FieldDescriptor {
    var MangledTypeName: RelativeDirectPointer<CChar>
    var Superclass: RelativeDirectPointer<CChar>
    var Kind: UInt16
    var FieldRecordSize: UInt16
    var NumFields: UInt32
    var fields: FieldRecord    //数组中存入的全是FieldRecord
}

struct FieldRecord {
    var flag: UInt32
    var MangledTypeName: RelativeDirectPointer<CChar>
    var fieldName: RelativeDirectPointer<CChar>
}

struct RelativeDirectPointer<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))
        }
    }
}

struct Person {
    var name = "ph"
    var age = 10
}

//强制按位转换,把Pserson的metadata绑定到StructMetadata上
let ptr = unsafeBitCast(Person.self as Any.Type, to: UnsafeMutablePointer<StructMetadata>.self)
let name = ptr.pointee.description.pointee.name.get()
let count = ptr.pointee.description.pointee.numFields
print(count)
print(String(cString: name))

let fieldName = ptr.pointee.description.pointee.fields.get().pointee.fields.fieldName.get()
print(String(cString: fieldName))