MethodSwizzle体现Swift与ObjC派发机制的区别

首先,实现一个swizzle方法替换People对象run()的IMP为runNew()的IMP,然后用两种方式调用run(),结果会是一样的吗?

代码如下:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let peo = People()

        peo.run()
        peo.perform(#selector(People.run))

        self.swizzle()

        peo.run()
        peo.perform(#selector(People.run))

    }
}

extension ViewController {

    func swizzle() {

        let cls = People.self
        let orgSel = #selector(People.run)
        let newSel = #selector(runNew)

        if let newMethod = class_getInstanceMethod(ViewController.self, newSel) {

            let newImp = method_getImplementation(newMethod)
            let type = method_getTypeEncoding(newMethod)

            class_replaceMethod(cls, orgSel, newImp, type)

        }
    }

    @objc func runNew() {
        print("run new")
    }
}

@objc class People: NSObject {
    @objc func run() {
        print("run")
    }
}

直接贴出代码运行结果:

run
run
run
run new

显然,都是调用run方法,两者结果是不一样的:
peo.run() -- run
peo.perform(#selector(People.run)) -- run new

谜底是什么

Swift的默认派发机制是直接派发(Direct Dispatch)
这里是NSObject的子类,是函数表派发,
ObjC的派发机制是消息机制派发(Message Dispatch),

在Swift中,这里run()走的是直接派发函数表派发,而perform走的是消息机制派发。
如果要更改run()的派发方式,可以在run()方法前面加上dynamic
@objc dynamic func run(),这时调用run()走的是消息机制派发。

再次运行:

run
run
run new
run new

更新

除了加上dynamic的方式,还可以用extension。extension NSObject子类的方法是消息机制派发。

extension People {
    @objc func run() {
        print("run")
    }
}

参考

深入理解 Swift 派发机制

你可能感兴趣的:(MethodSwizzle体现Swift与ObjC派发机制的区别)