swift class type isa-swizzling
class
是引用類型,生成的實例分布在 Heap(堆) 內存區域上,在 Stack(棧)只存放著一個指向堆中實例的指針。因為考慮到引用類型的動態性和 ARC 的原因,class
類型實例需要有一塊單獨區域存儲類型信息和引用計數。
在 Swift 中,class 類型的方法派發是通過 V-Table 來實現動態派發的。Swift 會為每一種類類型生成一個 Type 信息並放在靜態內存區域中,而每個類類型實例的 type 指針就指向靜態內存區域中本類型的 Type 信息。當某個類實例調用方法的時候,首先會通過該實例的 type 指針找到該類型的 Type 信息,然後通過信息中的 V-Table 得到方法的地址,並跳轉到相應的方法的實現地址去執行方法。
通過上面的分析,我們知道一個類類型的方法派發是通過頭部的 type 指針來決定的,如果我們將某個類實例的 type 指針指向另一個 type 會不會有什麽好玩的事情發生呢?哈哈 ~ 一起來試試 ~
class Wolf {
var name: String = "wolf"
func soul() {
print("my soul is wolf")
}
func headPointerOfClass() -> UnsafeMutablePointer<Int8> {
let opaquePointer = Unmanaged.passUnretained(self as AnyObject).toOpaque()
let mutableTypedPointer = opaquePointer.bindMemory(to: Int8.self, capacity: MemoryLayout<Wolf>.stride)
return UnsafeMutablePointer<Int8>(mutableTypedPointer)
}
}
class Fox {
var name: String = "fox"
func soul() {
print("my soul is fox")
}
func headPointerOfClass() -> UnsafeMutablePointer<Int8> {
let opaquePointer = Unmanaged.passUnretained(self as AnyObject).toOpaque()
let mutableTypedPointer = opaquePointer.bindMemory(to: Int8.self, capacity: MemoryLayout<Fox>.stride)
return UnsafeMutablePointer<Int8>(mutableTypedPointer)
}
}
let wolf = Wolf()
var wolfPtr = UnsafeMutableRawPointer(wolf.headPointerOfClass())
let fox = Fox()
var foxPtr = UnsafeMutableRawPointer(fox.headPointerOfClass())
foxPtr.advanced(by: 0).bindMemory(to: UnsafeMutablePointer<Wolf.Type>.self, capacity: 1).initialize(to: wolfPtr.advanced(by: 0).assumingMemoryBound(to: UnsafeMutablePointer<Wolf.Type>.self).pointee)
print(type(of: fox)) //Wolf
print(fox.name) //"fox"
fox.soul()
https://mp.weixin.qq.com/s/zIkB9KnAt1YPWGOOwyqY3Q
swift class type isa-swizzling