RxSwift 自定义 Delegate 实现
最近在学习 RxSwift, 一个很常用的例子就是通过 UITableView 各种数据的展示和事件的点击来学习。通常我们会通过原生的 delegate 来控制各种行为,比如通过 tableView(_:didSelectRowAt:)
这个方法来设置点击 cell 之后的自动反选,但既然是在学习 Reactive programming, 我们期待实现下面的效果:
myTableView.rx.didSelectedRowAtIndexPath.subscribe(onNext: { |
这看上去更简洁,更符合 RxSwift 的习惯,RxSwift 也提供了这种机制:DelegateProxy
, 让我们可以实现上面的代码。
事实上,RxSwift 为我们提供了一个 itemSelected
变量可以作为我们学习的对象
tableView.rx.itemSelected.subscribe(onNext: { path in |
通过查看 itemSelected
在 UITableView+Rx.swift 的源码我们可以看到,它其实就是 delegate message tableView:didSelectRowAtIndexPath:
的 Reactive wrapper,
其中 source 是通过delegate.methodInvoked
返回的 Observable
public var itemSelected: ControlEvent<IndexPath> { |
那这就解释的通,对 itemSelected 订阅来获取通知的方法。我们继续查看 delegate 定义
/// Reactive wrapper for `delegate`. |
可以看到 delegate 是原生 delegate 的 Reactive wrapper, 是一个继承了 DelegateProxy
的 computed property, 并且通过查资料得知,只能通过 proxyForObject
方法来创建它,然后我们继续了解 DelegateProxy
这个协议, 具体源码略长,这里就不附上,但我们了解到,它是 DelegateProxyType 的基本实现,并且了解到想要实现这个协议所必须实现的三个方法,我们试着自己定义自己的 RxDelegate:
class MyRxTableViewDelegateProxy: DelegateProxy<UITableView, UITableViewDelegate>, UITableViewDelegate, DelegateProxyType { |
需要注意的几点是:
自定义协议遵从
DelegateProxy
,DelegateProxyType
,和我们想要模仿的UITableViewDelegate
三个协议让 delegate proxy 获取原生delegate对象:
static func currentDelegate(for object: UITableView) -> UITableViewDelegate? {
return object.delegate
}设置 delegate proxy 对象
static func setCurrentDelegate(_ delegate: UITableViewDelegate?, to object: UITableView) {
object.delegate = delegate
}用于向RxCocoa注册我们自定义的DelegateProxyType
self.register {
MyRxTableViewDelegateProxy(parentObject: $0, delegateProxy: MyRxTableViewDelegateProxy.self) }
}
然后我们需要定义 rxDidSelectedRowAtIndexPath
和它的对象 rxDelegate
,
依据源码我们可以很容易试着对 UITableView 扩展
extension UITableView { |
而对于 Selector 方法,一个更好的写法是:
private extension Selector { |
所以我们的 rxDidSelectRowAtIndexPath
就变成了:
var rxDidSelectRowAtIndexPath: Observable<(UITableView, IndexPath)> { |
至此,我们自定义的 DelegateProxy 就可以进行原生 delegate 的功能了:
self.myTableView.rxDidSelectRowAtIndexPath.subscribe(onNext: { |