RxDataSource(3.0.1)版
RxDataSource 中数据源是如何和绑定的--tableView.rx.items: 第三种重载实现
《2》中分析了tableView.rx.items第一种重载的实现,现在分析一下第三种重载实现
public func items<DataSource: RxTableViewDataSourceType & UITableViewDataSource, O: ObservableType>
(dataSource: DataSource) //函数参数类型:RxTableViewReactiveArrayDataSourceSequenceWrapper
-> (_ source: O) -> Disposable //函数返回类型
where DataSource.Element == O.E {
return { source in
//1、先获取一下代理,确保存在(若不存在内部会创建并保存起来)
_ = self.delegate
//2、内部设置了tableView.dataSource,并订阅了source自己,nextEvent到来会执行后面的尾随闭包
return source.subscribeProxyDataSource(ofObject: self.base, dataSource: dataSource as UITableViewDataSource, retainDataSource: true) { [weak tableView = self.base] (_: RxTableViewDataSourceProxy, event) -> Void in
guard let tableView = tableView else {
return
}
//3、每次数据源有新数据到来时都会执行
//里面做的事情: 保存到来的数据,然后tableView.reload
dataSource.tableView(tableView, observedEvent: event)
}
}
}
首先它是一个f(a) -> ( f(b) -> c)类型的函数,return的 { source in ..... } 闭包 就是 f(b) -> c 类型的函数。
代码片段中进行了基本的注释解释,然后分步看一下。
1、_ = self.delegate
就这么短短的一行,却做了很多事情,这个delegate它负责tableview的代理事件,这个delegate你在tableview+rx里面找不到,因为它是来自scrollView+rx中的一个计算型属性:
/// For more information take a look at `DelegateProxyType` protocol documentation.
public var delegate: DelegateProxy<UIScrollView, UIScrollViewDelegate> {
return RxScrollViewDelegateProxy.proxy(for: base)
}
RxScrollViewDelegateProxy.proxy(for: base), base代表了tableview它自己,
RxScrollViewDelegateProxy 可以看成是一个特殊的字典,根据base 取值,内部实现如下:
// delegate和dataSource都用该方法获取/设置
public static func proxy(for object: ParentObject) -> Self {
MainScheduler.ensureExecutingOnScheduler()
//获取关联的代理/数据源
let maybeProxy = self.assignedProxy(for: object)
// Type is ideally be `(Self & Delegate)`, but Swift 3.0 doesn't support it.
let proxy: Delegate
// 存在
if let existingProxy = maybeProxy {
proxy = existingProxy
}
else {
// 不存在,创建代理,
proxy = castOrFatalError(self.createProxy(for: object))
// 设置关联
self.assignProxy(proxy, toObject: object)
assert(self.assignedProxy(for: object) === proxy)
}
// 获取object(tableView.delegate,dataSource)
let currentDelegate = self.currentDelegate(for: object)
// 确认proxy有值
let delegateProxy: Self = castOrFatalError(proxy)
// tableView.delegate被设置过,且和proxy不是同一个对象
if currentDelegate !== delegateProxy {
//把tableView.delegate存起来(叫做ForwardToDelegate)
delegateProxy.setForwardToDelegate(currentDelegate, retainDelegate: false)
assert(delegateProxy.forwardToDelegate() === currentDelegate)
//根据self是什么类型而定 数据源类型or代理类型 设置 tableView.delegate = proxy 或 tableView.dataSource = proxy
self.setCurrentDelegate(proxy, to: object)
assert(self.currentDelegate(for: object) === proxy)
assert(delegateProxy.forwardToDelegate() === currentDelegate)
}
// 返回被替换的代理对象
return delegateProxy
}
这是一个很重要的方法,查找数据源和代理都用该方法,
public static func proxy(for object: ParentObject) -> Self 这个方法是DelegateProxyType协议的extension实现的
那么如何知道是要获取数据源还是获取代理呢,其实是根据self的不同,从而获取到不同的内容,这里的self 是RxScrollViewDelegateProxy类型,当获取数据源时,self会是其他类型,但是他们都实现了DelegateProxyType协议,所以用的时候,各取各的。
let maybeProxy = self.assignedProxy(for: object),点击进入self.assignedProxy(for: object)实现,
fileprivate static func assignedProxy(for object: ParentObject) -> Delegate? {
let maybeDelegate = objc_getAssociatedObject(object, self.identifier)
return castOptionalOrFatalError(maybeDelegate.map { $0 as AnyObject })
}
fileprivate static func assignProxy(_ proxy: Delegate, toObject object: ParentObject) {
objc_setAssociatedObject(object, self.identifier, proxy, .OBJC_ASSOCIATION_RETAIN)
}
这个函数设置和获取代理时,用到了runtime的关联方法,将它自身创建的代理和数据源关联到了tableView身上,使用的key 是用self (RxScrollViewDelegateProxy或者数据源代理类型RxTableViewDataSourceProxy)产生一个标识。这个identifier是如何产生的可以自己查看。
检查tableView.delegate 是否被人为设置过原始delegate,如果有,它会保存起来。然后它将自己的创建的代理proxy设置给tableview.delegate,proxy代理执行时,它会同步通知原始delegate。
这里也会产生一个小问题,就是如果我们同时使用rx和设置tableview.delegate = self(xxx)时,要保证我们自己写的tableview.delegate = self(xxx)在设置rx的前面,否则rx会失效
2、 return source.subscribeProxyDataSource( .......
这个返回类型其实是一个Disposable
return source.subscribeProxyDataSource(ofObject: self.base,
dataSource: dataSource as UITableViewDataSource,
retainDataSource: true)
{ [weak tableView = self.base] (_: RxTableViewDataSourceProxy, event) -> Void in
guard let tableView = tableView else {
return
}
dataSource.tableView(tableView, observedEvent: event)
}
subscribeProxyDataSource函数的原型:
func subscribeProxyDataSource<DelegateProxy: DelegateProxyType>(ofObject object: DelegateProxy.ParentObject,
dataSource: DelegateProxy.Delegate,
retainDataSource: Bool,
binding: @escaping (DelegateProxy, Event<E>) -> Void)
-> Disposable
在source执行完subscribeProxyDataSource后正好返回了一个 Disposable.
subscribeProxyDataSource 函数 binding 其实是一个尾闭包。
类型:binding: @escaping (DelegateProxy, Event<E>) -> Void)
所以导致我们看到调用source.subscribeProxyDataSource的写法有点别扭了。下面换种形式
return source.subscribeProxyDataSource(ofObject: self.base,
dataSource: dataSource as UITableViewDataSource,
retainDataSource: true)
{ [weak tableView = self.base] (_: RxTableViewDataSourceProxy, event) -> Void in
guard let tableView = tableView else {
return
}
dataSource.tableView(tableView, observedEvent: event)
}
换成普通形式:
typealias BindingType = @escaping (DelegateProxy, Event<E>) -> Void
let binding: BindingType =
{ (_: RxTableViewDataSourceProxy, event) -> Void in
guard let tableView = tableView else {
return
}
dataSource.tableView(tableView, observedEvent: event)
}
return source.subscribeProxyDataSource(ofObject: self.base,
dataSource: dataSource as UITableViewDataSource,
retainDataSource: true,
binding: binding)
其中:
(_: RxTableViewDataSourceProxy, event) -> Void
这里_: RxTableViewDataSourceProxy 忽略了值,只限定了类型
这里传入的类型,就和之前获取代理还是数据源产生了联系了,此处binding传入的闭包函数,类型限定了RxTableViewDataSourceProxy,所以导致subscribeProxyDataSource函数内实现时,
let proxy = DelegateProxy.proxy(for: object)获取到的就是数据源DataSource,而不是delegate。
不光是这里做了类型限制,打开DelegateProxyType文件:
public protocol DelegateProxyType: class {
associatedtype ParentObject: AnyObject
associatedtype Delegate: AnyObject // 这里也做了一些限制,真正实现时,这里会被实现协议的class落实成UIScrollViewDelegate或者UItableViewDataSoucrce 等
.....
}
再来看RxScrollViewDelegateProxy和RxTableViewDataSourceProxy 文件
open class RxScrollViewDelegateProxy
: DelegateProxy<UIScrollView, UIScrollViewDelegate>
, DelegateProxyType
, UIScrollViewDelegate {
......
}
open class RxTableViewDataSourceProxy
: DelegateProxy<UITableView, UITableViewDataSource>
, DelegateProxyType
, UITableViewDataSource {
.....
}
//上面两个都是继承DelegateProxy
open class DelegateProxy<P: AnyObject, D: AnyObject>: _RXDelegateProxy {
public typealias ParentObject = P
public typealias Delegate = D
}
实现DelegateProxyType协议的class,在定义时就定义好了DelegateProxyType 中用到的两种类型,所以说,他们虽然都用的事同一套方法获取代理,但是由于类型不同,获取到关联的内容也就不同。