方法交换是oc的技术,可以借助runtime的动态派发的特性实现两个方法的实现部分互换;

那么在swift如果实现呢?

在我们深入挖掘实现细节之前,需要对selectors相关的概念做一些说明

什么是selectors

selector表示的一个类对象的方法的名称,selector没有具体实现,不做任何事情,唯一的目标的就是标识一个方法

为什么使用方法交换(method swizzling)

有以下场景可以用到:

方便的在App监测一个ViewController到另一个ViewController的切换;

具体方法是修改viewWillAppearselector,添加一些监控行为

实现如下:

1
2
3
4
@objc dynamic func _swizzled_viewWillAppear(_ animated: Bool) {
_swizzled_viewWillAppear(animated)
//你要监控的行为
}
  • @objc说明用到oc的特性方法

  • dynamic说明用到了动态

  • 这不是会循环调用么?为什么要调用自己? 不会,因为切换后内括号内的调用其实是调用了原有的ViewWillAppear

通过method_exchangeImplementations方法,实现两个方法的交换

1
2
3
4
5
let selector1 = #selector(UIViewController.viewWillAppear(_:))
let selector2 = #selector(UIViewController.swizzled_viewWillAppear(:))
let originalMethod = class_getInstanceMethod(UIViewController.self, selector1)!
let swizzleMethod = class_getInstanceMethod(UIViewController.self, selector2)!
method_exchangeImplementations(originalMethod, swizzleMethod)

前面的实现整理到一起就完成了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
extension UIViewController {
@objc dynamic func _swizzled_viewWillAppear(_ animated: Bool) {
_swizzled_viewWillAppear(animated)
//你要监控的行为
}

static func swizzleViewWillAppear() {
let selector1 = #selector(UIViewController.viewWillAppear(_:))
let selector2 = #selector(UIViewController._swizzled_viewWillAppear(_:))
let originalMethod = class_getInstanceMethod(UIViewController.self, selector1)!
let swizzleMethod = class_getInstanceMethod(UIViewController.self, selector2)!
method_exchangeImplementations(originalMethod, swizzleMethod)
}
}

别忘了调用方法交换

1
UIViewController.swizzleViewWillAppear()

现在,UIViewController的所有实例和子类实例调用viewWillAppear时,都会触发 _swizzled_viewWillAppear

备注:

有两点要注意:

  • 如果你要实现方法交换,你的类必须继承自NSObject

  • 你要交换的方法必须具有动态属性@objc dynamic