首先,实现一个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")
}
}