美文网首页
swift底层探索 08-根据Mirror原理还原TargetS

swift底层探索 08-根据Mirror原理还原TargetS

作者: Henry________ | 来源:发表于2021-07-16 01:08 被阅读0次

    在swift源码中有这样一段代码,可以看到所有的类型都是有元类型的,枚举结构体都被已经被定义了,下面就通过mirror来还原TargetStructMetadata结构。

    1、Mirror

    struct Teacher{
        var age = 18
        var name = "henry"
        var height = 1.8
        var hobby = "woman"
    }
    
    let t = Teacher()
    let mirror = Mirror(reflecting: t)
    
    for pro in mirror.children{
       print("\(pro.label):\(pro.value)")
    }
    

    为什么Mirror可以获取到结构体的属性名称?

    1.1 Mirror源码

    public struct Mirror {
       //初始化方法
      public init(reflecting subject: Any) {
        if case let customized as CustomReflectable = subject {
          self = customized.customMirror
        } else {
          self = Mirror(internalReflecting: subject)
        }
      }
    }
    

    1.2 Mirror初始化

    extension Mirror {
      internal init(internalReflecting subject: Any,
                  subjectType: Any.Type? = nil,
                  customAncestor: Mirror? = nil)
    {
    // type(of:)获取到subject的真实类型
        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
          }
          if let customAncestor = customAncestor {
            if superclass == customAncestor.subjectType {
              return customAncestor
            }
            if customAncestor._defaultDescendantRepresentation == .suppressed {
              return customAncestor
            }
          }
          return Mirror(internalReflecting: subject,
                        subjectType: superclass,
                        customAncestor: customAncestor)
        }
     // 获取并解析显示的样式,并设置Mirror的其他属性
        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
    }
    
    • type(of:) 获取到subject的真实类型

    2、TargetStructMetadata结构

    源码中继承关系比较复杂,因为设计到继承和一些模板类,所以只放出一张结构图:


    转换为代码形式:

    struct StructMetaData{
        var kind : Int32
        var description : UnsafePointer<StructDescriptor>
    }
    
    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
    }
    
    struct FieldDescriptor {
        var MangledTypeName: RelativePointer<CChar>
        var Superclass: RelativePointer<CChar>
        var kind: UInt16
        var fieldRecordSize: Int16
        var numFields: Int32
        var fields: FieldRecord //连续的存储空间
    }
    
    struct FieldRecord {
        var Flags: Int32
        var MangledTypeName: RelativePointer<CChar>
        var FieldName: RelativePointer<CChar>
    }
    
    
    struct RelativePointer<T> {
        var offset:Int32
        
        mutating public func get() -> UnsafePointer<T> {
            let offSet = self.offset
            
            return withUnsafePointer(to: &self){ ptr in
                UnsafeRawPointer(ptr).advanced(by: numericCast(offSet)).assumingMemoryBound(to: T.self)
            }
        }
    }
    

    3、还原结构

    根据源码要先获取元类指针,2种方式均可。swift指针使用起来有点难度(摊牌了我是个菜鸡。。。)swift底层探索 06 - 指针简单使用

    1. withUnsafeMutablePointer
    var type = Teacher.self
    //指向元类指针的指针
    let a = withUnsafeMutablePointer(to: &type) { ptr in
        UnsafeRawPointer(ptr).bindMemory(to: UnsafeMutablePointer<StructMetaData>.self, capacity: 1)
    }
    // 获取元类指针
    let metaPtr = a.pointee
    
    • 注意:a是 : 指向元类指针的指针
    1. unsafeBitCast按位强转
    let metaPtr = unsafeBitCast(Teacher.self as Any.Type, to: UnsafePointer<StructMetaData>.self)
    
    • unsafeBitCast需要两个参数的内存大小相同。必须使用:Teacher.self as Any.Type进行转换,因为根据测试发现Teacher.self获取内存大小为0(这个地方是真的坑),如下图:
    Teacher.self as Any.Type 动作

    根据sil查看发现 Teacher.self as Any.Type在底层的操作;

    3.1 获取结构体名

    let structName = metaPtr.pointee.description.pointee.name.get()
    let structNameStr = String(cString: structName)
    print("获取结构体名:\(structNameStr)")
    

    输出:


    3.2 获取内部属性个数

    let cnt = metaPtr.pointee.description.pointee.NumFields
    print("获取结构体属性个数:\(cnt)")
    

    输出:


    3.3 获取所有属性

    let fieldsPtr = b.pointee.description.pointee.Fields.get()
    for i in 0..<cnt {
        let record = withUnsafePointer(to: &fieldsPtr.pointee.fields) {
            UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: FieldRecord.self).advanced(by: numericCast(i)))
        }
        let recordNameStr = String(cString: record.pointee.FieldName.get())
        let manNameStr = String(cString: record.pointee.MangledTypeName.get())
        print("类型名:\(recordNameStr) ----  类型类型:\(manNameStr)")
    }
    

    输出:


    • si : 其实就是Int
    • ss : 其实就是String
    • sd : 其实就是Double

    demo下载-github

    相关文章

      网友评论

          本文标题:swift底层探索 08-根据Mirror原理还原TargetS

          本文链接:https://www.haomeiwen.com/subject/qldvpltx.html