ReactiveX 学习笔记(37)RxSwift 的 share 和 RxCocoa 的 Driver
冷数据流,热数据流
- 冷数据流不能共享数据,热数据流能共享数据
- 冷数据流需要有订阅者才能发布数据,热数据流无需订阅者即可发布数据
publish, connect, refCount, replay
Understanding Connectable Observable Sequences in RxSwift
- 普通数据流调用 publish 操作符后变为可连接数据流。
- 可连接数据流调用 connect 操作符后变为热数据流。热数据流可以在所有订阅者中共享所发布的数据。
- 可连接数据流调用 refCount 操作符后具有引用计数功能,订阅数从0到1时自动连接变为热数据流,从1到0时自动断开连接重新变回可连接数据流。
- 可连接数据流或热数据流调用 replay 操作符后具有缓存功能,能缓存一部分或全部所发布的数据,新的订阅者在订阅时能够接收到订阅之前缓冲区的数据。
share, replay, share(replay:scope:)
RxSwift: share vs replay vs shareReplay
Understanding the RxSwift share operator
RxSwift: share()-ing is Caring
- share 相当于 publish + refCount,有引用计数功能,订阅数从0到1时自动连接,从1到0时自动断开连接。
- replay 没有引用计数功能,需要调用 connect 之后才能连接。
- replay 有缓存功能,可以指定缓存的大小。
- share(replay:scope:) 相当于 share + replay,同时具有引用计数功能和缓存功能。
scope = .whileConnected 只有在连接时才缓存数据,断开连接时缓存被释放,重新连接后新的订阅者不会接收到订阅之前发布的数据。
scope = .forever 即使断开连接时缓存仍然保持,重新连接后新的订阅者会接收到订阅之前发布的数据。
Driver
Driver 是 RxCocoa 中的一个 Trait,即具有某些特性的数据流。
Driver 数据流的特性
- 不会出错
- 在主线程观察数据
- 共享副作用
share(replay: 1, scope: .whileConnected)
示例
let results = query.rx.text
.throttle(.milliseconds(300), scheduler: MainScheduler.instance)
.flatMapLatest { query in
fetchAutoCompleteItems(query)
.observeOn(MainScheduler.instance) // results are returned on MainScheduler
.catchErrorJustReturn([]) // in the worst case, errors are handled
}
.share(replay: 1) // HTTP requests are shared and results replayed
// to all UI elements
results
.map { "\($0.count)" }
.bind(to: resultCount.rx.text)
.disposed(by: disposeBag)
results
.bind(to: resultsTableView.rx.items(cellIdentifier: "Cell")) { (_, result, cell) in
cell.textLabel?.text = "\(result)"
}
.disposed(by: disposeBag)
这段代码的功能为发出 http 请求,将结果数据与两个控件绑定
- .observeOn(MainScheduler.instance)
在主线程中监听数据, - .catchErrorJustReturn([])
出错时返回空数组 - .share(replay: 1)
结果数据需要与两个控件绑定,必须使用热数据流来共享数据。如果使用冷数据流来绑定两个控件将导致发送两次 http 请求
let results = query.rx.text.asDriver() // This converts a normal sequence into a `Driver` sequence.
.throttle(.milliseconds(300), scheduler: MainScheduler.instance)
.flatMapLatest { query in
fetchAutoCompleteItems(query)
.asDriver(onErrorJustReturn: []) // Builder just needs info about what to return in case of error.
}
results
.map { "\($0.count)" }
.drive(resultCount.rx.text) // If there is a `drive` method available instead of `bind(to:)`,
.disposed(by: disposeBag) // that means that the compiler has proven that all properties
// are satisfied.
results
.drive(resultsTableView.rx.items(cellIdentifier: "Cell")) { (_, result, cell) in
cell.textLabel?.text = "\(result)"
}
.disposed(by: disposeBag)
这段代码改用 Driver 来完成同样的功能。
- .asDriver()
将数据流转换为 Driver 数据流,后者是一种共享数据流,具有共享数据的功能 - .asDriver(onErrorJustReturn: [])
出错时返回空数组,Driver 数据流能在主线程中监听数据, - .drive(resultCount.rx.text)
Driver 必须使用 drive 方法来绑定控件
Signal
Signal 是 RxCocoa 中的一个 Trait,即具有某些特性的数据流。
Signal 数据流的特性
- 不会出错
- 在主线程观察数据
- 共享计算资源
share(scope: .whileConnected)
- 没有缓存,新的订阅者不会接收订阅之前所发布的数据