ios - `.drive()` 和 `.bind(to:)` 之间的区别
问题描述
我现在正在学习 RxSwift。
你什么时候用.drive(something)
,什么时候用.bind(to: something)
?
例子:
let disposeBag = DisposeBag()
let isEnabled = BehaviorRelay(value: true)
let button = UIButton()
// what is the benefit of this:
isEnabled.asDriver().drive(button.rx.isEnabled).disposed(by: disposeBag)
// over this:
isEnabled.bind(to: button.rx.isEnabled).disposed(by: disposeBag)
// or is the above better?
使用 RxSwift、驱动程序和绑定到的答案并没有真正的帮助。我不明白为什么asDriver()
甚至需要添加才能使它成为一个不会失败的东西。
解决方案
来自 RxSwift 的 GitHub 页面
这是最精细的特征。它的目的是提供一种在 UI 层中编写响应式代码的直观方式,或者在任何您想要对驱动应用程序的数据流进行建模的情况下。
- 不能出错。
- 观察发生在主调度程序上。
- 分享副作用(share(replay: 1, scope: .whileConnected))。
再次从同一页面复制
它的预期用例是对驱动应用程序的序列进行建模。
现在回到差异?
驱动程序确保仅在主线程上发生观察:
Drive 是 RxSwift 中确保观察仅发生在的特征之一MainThread
,这意味着无论在哪个线程事件发出和触发驱动程序,驱动程序都将始终确保将事件转发到链中的下一个运算符或其在 main 上的订阅块线。
在 Rx 中,所有事件都在事件发生的同一线程上传播。因此,如果您在说线程 (100) 上使用 触发主题subject.onNext(
,则其订阅块将在同一线程 (100) 上调用,直到并且除非您使用observedOn
orsubscribedOn
运算符来确保手动线程切换。
如果您从 viewModel 中的 observables/subjects 驱动 UI 组件,那么驱动程序非常有意义。假设您在后台线程上进行 API 调用以从服务器获取数据,您不想在后台线程上访问您的 UI 组件,将您的 observables/subjects 连接/转换为驱动程序(使用asDriver
和传递onErrorJustReturn
)并通过驱动程序驱动您的 UI 组件将确保您的 UI 组件始终在主线程上访问
不能出错。
通常,当发生错误时,订阅将被终止,如果您正在驱动您的 UI 组件,您不希望每次发生错误事件时订阅/绑定都会中断。
示例:假设您通过 CoreData 驱动 tableView,并且由于某种原因从 CoreData 获取数据时发生错误,如果您不使用驱动器并且使用了平面bind(to:
,它将onError
被触发并且它与 UIComponent 的绑定将被破坏。如果您再次获取数据,您将不得不重新建立此绑定。对于获取/获取数据时的 UI 组件错误应该没有任何区别。它应该只是一个改变其状态的事件流。
bindTo
只不过是语法糖衣,subscribe
所以如果你使用bindTo
或subscribe
驱动 UI 组件,你将失去所有drive
固有的好处。
您始终可以使用observedOn
来确保手动切换线程,main
并且可能有一些重试机制来建立订阅回/在发生错误时保留订阅,但最终您将最终编写自己的驱动器特征
什么时候应该使用驱动器,什么时候应该使用 bindTo
拇指规则是您是否试图驱动 UI 组件使用drive
else use bindTo
。通常,如果您希望您的订阅仅在主线程上发生并且不希望您的订阅出错(例如驱动 UI 组件),请使用driver
else 坚持使用bindTo
或subscribe
编辑1:
OP在评论中的问题:
我的示例中的 asDriver() 确保在主线程上观察到 isEnabled 并且我不必传递 onErrorJustReturn 因为 BehaviorRelay 也不能失败?在这种情况下 drive() 具有主线程的好处,但没有故障安全的好处?
在我的示例中,确保在主线程上观察到 isEnabled -是
我不必传递 onErrorJustReturn 因为 BehaviorRelay 也不能失败?-宾果游戏
如果您对 BehaviorRelay 进行更深入的检查,您会发现
/// BehaviorRelay 是
BehaviorSubject
. /// /// 不像BehaviorSubject
它不能因错误或完成而终止。
很明显 BehaviorRelay 不能出错,因此编译器足够聪明,可以理解而不是要求onErrorJustReturn
. 如果您真的想看到一种用途BehaviorSubject
,编译器会要求它:)
感谢Daniel指出我的错误,这种驱动力并不是确保观察只发生在MainThread
因此编辑我的答案以反映相同的唯一特征。谢谢