美文网首页
深度探究HandyJSON(五) 解析 class

深度探究HandyJSON(五) 解析 class

作者: Lin__Chuan | 来源:发表于2018-12-25 20:59 被阅读14次

书接上文, class 和 struct 还是有些不同.

回顾一下, 如何在内存上为实例的属性赋值呢?

  • 获取到属性的名称和类型.
  • 找到实例在内存中的 headPointer, 通过属性的类型计算内存中的偏移值, 确定属性在内存中的位置.
  • 在内存中为属性赋值.

那么 HandyJSON 内部是怎么处理的呢?

第0步: 定义 Model

class PersonClass {
    var isBoy: Bool = true
    var age: Int = 0
    var height: Double = 130.1
    var name: String = "jack"
}

第 1 步: 获取属性数量, 以及属性偏移矢量.

struct _ClassContextDescriptor {
    var flags: Int32
    var parent: Int32
    var mangledName: Int32
    var fieldTypesAccessor: Int32
    var superClsRef: Int32
    var reservedWord1: Int32
    var reservedWord2: Int32
    var numImmediateMembers: Int32
    var numberOfFields: Int32
    var fieldOffsetVector: Int32
}

let personType = PersonClass.self as Any.Type
let pointer = unsafeBitCast(personType, to: UnsafePointer<Int>.self)

let base = pointer.advanced(by: 8)  // contextDescriptorOffsetLocation

let relativePointerOffset = base.pointee - Int(bitPattern: base)
let descriptor = UnsafeRawPointer(base).advanced(by: relativePointerOffset).assumingMemoryBound(to: _ClassContextDescriptor.self)

// 以 _StructContextDescriptor 类型访问内存数据
print("\n _ClassContextDescriptor \n", descriptor.pointee)

第 2 步: 获取属性偏移值

extension UnsafePointer {
    init<T>(_ pointer: UnsafePointer<T>) {
        self = UnsafeRawPointer(pointer).assumingMemoryBound(to: Pointee.self)
    }
}

let contextDescriptor = descriptor.pointee
let numberOfFields = Int(contextDescriptor.numberOfFields)
let fieldOffsetVector = Int(contextDescriptor.fieldOffsetVector)

// 成员变量的偏移值
let fieldOffsets = (0..<numberOfFields).map {
    return Int(UnsafePointer<Int>(pointer)[fieldOffsetVector + $0])
}
print("\n fieldOffsets \n", fieldOffsets)
// // [16, 24, 32, 40]

第 3 步: 将属性名字和类型进行包装

struct PropertyDescription {
    public let key: String
    public let type: Any.Type
    public let offset: Int
}

// 类对象
let selfType = unsafeBitCast(pointer, to: Any.Type.self)  // PersonClass.Type

// 属性的包装
var propertyDescriptions: [PropertyDescription] = []

class NameAndType {
    var name: String?
    var type: Any.Type?
}

// 下面这是编译器特性
// 可跳过桥接文件和.h头文件与C代码交互
@_silgen_name("swift_getFieldAt")
func _getFieldAt(
    _ type: Any.Type,
    _ index: Int,
    _ callback: @convention(c) (UnsafePointer<CChar>, UnsafeRawPointer, UnsafeMutableRawPointer) -> Void,
    _ ctx: UnsafeMutableRawPointer
)

for i in 0..<numberOfFields {
    // 属性name, type 的包装类
    var nameAndType = NameAndType()
    
    // 获取属性name, type
    _getFieldAt(selfType, i, { (namePointer, typePointer, nameTypePointer) in
        let name = String(cString: namePointer)
        let type = unsafeBitCast(typePointer, to: Any.Type.self)
        let nameType = nameTypePointer.assumingMemoryBound(to: NameAndType.self).pointee
        nameType.name = name
        nameType.type = type
    }, &nameAndType)
    
    // 将name , type, offset进行包装
    if let name = nameAndType.name, let type = nameAndType.type {
        propertyDescriptions.append(PropertyDescription(key: name, type: type, offset: fieldOffsets[i]))
    }
}

print("\n propertyDescriptions \n", propertyDescriptions)

class 和 struct 的不同点来了, class 中属性的 offset 可能会发生变化.

struct _class_rw_t {
    var flags: Int32
    var version: Int32
    var ro: UInt
    // other fields we don't care
    
    func class_ro_t() -> UnsafePointer<_class_ro_t>? {
        return UnsafePointer<_class_ro_t>(bitPattern: self.ro)
    }
}

struct _class_ro_t {
    var flags: Int32
    var instanceStart: Int32
    var instanceSize: Int32
    // other fields we don't care
}

struct _Class {
    var kind: Int
    var superclass: Any.Type?
    var reserveword1: Int
    var reserveword2: Int
    var databits: UInt
    // other fields we don't care
    
    func class_rw_t() -> UnsafePointer<_class_rw_t>? {
        if MemoryLayout<Int>.size == MemoryLayout<Int64>.size {
            let fast_data_mask: UInt64 = 0x00007ffffffffff8
            let databits_t: UInt64 = UInt64(self.databits)
            return UnsafePointer<_class_rw_t>(bitPattern: UInt(databits_t & fast_data_mask))
        } else {
            return UnsafePointer<_class_rw_t>(bitPattern: self.databits & 0xfffffffc)
        }
    }
}

上面是 class 的内部信息. 我们要获得实例在内存中的起始位置.

let personClsPtr = UnsafePointer<_Class>(pointer)
let instanceStartPosition = personClsPtr.pointee.class_rw_t()?.pointee.class_ro_t()?.pointee.instanceStart
print("\n instanceStartPosition \n", instanceStartPosition)

继而获取真正的属性信息

// 获取全部属性
var realPropertyDescriptions: [PropertyDescription] = []

if let firstInstanceStart = instanceStartPosition,
    let firstPropertyOffset = propertyDescriptions.first?.offset {
    realPropertyDescriptions = propertyDescriptions.map({ (propertyDesc) ->
        PropertyDescription in
        let offset = propertyDesc.offset - firstPropertyOffset + Int(firstInstanceStart)  
        // 在这里 firstPropertyOffset 和 firstInstanceStart 相同, 所以相当于 offset 没变.
        return PropertyDescription(key: propertyDesc.key, type: propertyDesc.type, offset: offset)
    })
} else {
    realPropertyDescriptions = propertyDescriptions
}
print("\n realPropertyDescriptions \n", realPropertyDescriptions)

第 4 步: 将 JSON 数据进行解析

这部分和 struct 是一致的, 就不多说.

// 获取头指针
func headPointerOfClass<T>(instance: T) -> UnsafeMutablePointer<Int8> {
    
    let opaquePointer = Unmanaged.passUnretained(instance as AnyObject).toOpaque()
    let mutableTypedPointer = opaquePointer.bindMemory(to: Int8.self, capacity: MemoryLayout<T>.stride)
    return UnsafeMutablePointer<Int8>(mutableTypedPointer)
}

// 获取头指针
var personClass = PersonClass()
let rawPointer = headPointerOfClass(instance: personClass)

// 获取数据
let dict: [String: Any] = ["isBoy": true, "name": "lili", "age": 18, "height": 100.123]

// 遍历属性
for property in realPropertyDescriptions {
    let propAddr = rawPointer.advanced(by: property.offset)
    
    if let rawValue = dict[property.key] {
        // 写入值
        extensions(of: property.type).write(rawValue, to: propAddr)
    }
}
print("\n person \n", personClass.height) // 写入成功

protocol AnyExtensions {}

extension AnyExtensions {
    public static func write(_ value: Any, to storage: UnsafeMutableRawPointer) {
        guard let this = value as? Self else {
            print("类型转换失败, \(type(of: value))无法转为\(Self.self)")
            
            return
        }
        
        storage.assumingMemoryBound(to: self).pointee = this
    }
}
func extensions(of type: Any.Type) -> AnyExtensions.Type {
    struct Extensions : AnyExtensions {}
    var extensions: AnyExtensions.Type = Extensions.self
    
    withUnsafePointer(to: &extensions) { pointer in
        UnsafeMutableRawPointer(mutating: pointer).assumingMemoryBound(to: Any.Type.self).pointee = type
    }
    return extensions
}

相关文章

网友评论

      本文标题:深度探究HandyJSON(五) 解析 class

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