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

posted @ 2018-09-19 15:13  zzfx  阅读(240)  评论(0编辑  收藏  举报