书接上文, 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
}
网友评论