首页 > 解决方案 > `.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()甚至需要添加才能使它成为一个不会失败的东西。

标签: iosswiftrx-swiftrx-cocoa

解决方案


来自 RxSwift 的 GitHub 页面

这是最精细的特征。它的目的是提供一种在 UI 层中编写响应式代码的直观方式,或者在任何您想要对驱动应用程序的数据流进行建模的情况下。

  1. 不能出错。
  2. 观察发生在主调度程序上。
  3. 分享副作用(share(replay: 1, scope: .whileConnected))。

再次从同一页面复制

它的预期用例是对驱动应用程序的序列进行建模。

现在回到差异?

驱动程序确保仅在主线程上发生观察:

Drive 是 RxSwift 中确保观察仅发生在的特征之一MainThread,这意味着无论在哪个线程事件发出和触发驱动程序,驱动程序都将始终确保将事件转发到链中的下一个运算符或其在 main 上的订阅块线。

在 Rx 中,所有事件都在事件发生的同一线程上传播。因此,如果您在说线程 (100) 上使用 触发主题subject.onNext(,则其订阅块将在同一线程 (100) 上调用,直到并且除非您使用observedOnorsubscribedOn运算符来确保手动线程切换。

如果您从 viewModel 中的 observables/subjects 驱动 UI 组件,那么驱动程序非常有意义。假设您在后台线程上进行 API 调用以从服务器获取数据,您不想在后台线程上访问您的 UI 组件,将您的 observables/subjects 连接/转换为驱动程序(使用asDriver和传递onErrorJustReturn)并通过驱动程序驱动您的 UI 组件将确保您的 UI 组件始终在主线程上访问

不能出错。

通常,当发生错误时,订阅将被终止,如果您正在驱动您的 UI 组件,您不希望每次发生错误事件时订阅/绑定都会中断。

示例:假设您通过 CoreData 驱动 tableView,并且由于某种原因从 CoreData 获取数据时发生错误,如果您不使用驱动器并且使用了平面bind(to:,它将onError被触发并且它与 UIComponent 的绑定将被破坏。如果您再次获取数据,您将不得不重新建立此绑定。对于获取/获取数据时的 UI 组件错误应该没有任何区别。它应该只是一个改变其状态的事件流。

bindTo只不过是语法糖衣,subscribe所以如果你使用bindTosubscribe驱动 UI 组件,你将失去所有drive固有的好处。

您始终可以使用observedOn来确保手动切换线程,main并且可能有一些重试机制来建立订阅回/在发生错误时保留订阅,但最终您将最终编写自己的驱动器特征

什么时候应该使用驱动器,什么时候应该使用 bindTo

拇指规则是您是否试图驱动 UI 组件使用driveelse use bindTo。通常,如果您希望您的订阅仅在主线程上发生并且不希望您的订阅出错(例如驱动 UI 组件),请使用driverelse 坚持使用bindTosubscribe

编辑1:

OP在评论中的问题:

我的示例中的 asDriver() 确保在主线程上观察到 isEnabled 并且我不必传递 onErrorJustReturn 因为 BehaviorRelay 也不能失败?在这种情况下 drive() 具有主线程的好处,但没有故障安全的好处?

在我的示例中,确保在主线程上观察到 isEnabled -

我不必传递 onErrorJustReturn 因为 BehaviorRelay 也不能失败?-宾果游戏

如果您对 BehaviorRelay 进行更深入的检查,您会发现

/// BehaviorRelay 是BehaviorSubject. /// /// 不像BehaviorSubject它不能因错误或完成而终止。

很明显 BehaviorRelay 不能出错,因此编译器足够聪明,可以理解而不是要求onErrorJustReturn. 如果您真的想看到一种用途BehaviorSubject,编译器会要求它:)

感谢Daniel指出我的错误,这种驱动力并不是确保观察只发生在MainThread因此编辑我的答案以反映相同的唯一特征。谢谢


推荐阅读