在 init 之外绑定 ViewModel 事件
Binding ViewModel events outside of the init
我在我的项目中使用了 RxSwift 和 Swinject。我绑定输入/输出的方式与 RxSwift 给出的示例不完全相同。在RxExample/GitHubSignup中,绑定是在init()
中完成的,对吗?但是我发现很难实现,因为我使用的是Swinject+SwinjectStoryboard对View Controller做Dependency Injection。因此,init()
不可用,因为实例化视图模型的是 Swinject 容器。那么,除了使用 init()
之外,还有没有办法将视图控制器和视图模型绑定在一起?
我在想我也许可以使用 var
而不是 let
作为输出可观察对象,并制作一个 func bind(observables: [Observable])
或将执行从输入到输入的绑定和转换的东西输出代替。但是因为它们将是 var 而不是 let,这意味着我们似乎被允许在整个代码中更改绑定。不像我们只使用 let 并在 init()
中绑定它们。而且,通过使用函数而不是初始化程序,我必须将依赖项存储到成员变量中。如果我使用初始化程序,我可以只转换 map
或 flatMap
.
内部的依赖项
我还有一个问题。说,如果我有这个:
class MyViewController: UIViewController {
@IBOutlet weak var refreshButton: UIButton!
@IBOutlet weak var tableView: UITableView!
var viewModel: MyViewModel!
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
viewModel = MyViewModel(refreshTap: refreshButton.rx.tap, dataProvider: ApiAdapter().getData)
}
private func setupEvents() {
viewModel.tableDTOs.bind(to: tableView.rx.items(
cellIdentifier: reuseId, cellType: TableViewCell.self)) { _, dto, cell in
cell.fill(with: dto)
}.disposed(by: disposeBag)
}
}
final class MyViewModel {
let tableDTOs: Observable<[TableDTO]>
init(refreshTap: Observable<Void>, dataProvider: () -> Observable<[TableDTO]>) {
tableDTOs = Observable.merge(.just(), refreshTap) //Merge with .just to emit at once for initial values
.flatMapLatest { dataProvider().asDriver() }
}
}
所以在这种情况下,如果dataProvider返回complete
或error
,disposable会被处理掉,对吧?因此场景将无响应,因为 UI 已经解除绑定。知道如何解决这个问题吗?
谢谢。
So, is there a way to bind the view controller and view model together besides using init()
?
是的。为视图模型提供一个接受输入和 returns 输出的函数。
But because they will be vars and not lets, that means it seems like we are permitted to change the bindings throughout the code.
永远不要让 Observable(或 Subject,或 Observer)成为 var
总是使用 let
函数式响应式编程是一种函数式范例,所以没有变量。
So in this case, if the dataProvider returned complete or error, the disposable will be disposed, right? So the scene will be unresponsive because the UI is already unbound. Any idea how to fix that?
是也不是。如果 dataProvider 发出完成的事件,则不会处理,因为 flatMapLatest
仅在其输入的 all 完成时处理。由于 refreshTap
尚未完成,flatMapLatest
将继续接受来自它的事件并为每个事件调用它的闭包。
如果 dataProvider 发出错误事件,将 处理,因为错误事件会使链短路。但是,由于您在 dataProvider 上使用了 .asDriver()
,因此从闭包返回的驱动程序不可能发出错误事件。你安全了。
阻止错误破坏链的其他方法是使用 .materialize()
或任何 .catchError
运算符。例如:
.flatMapLatest {
dataProvider
.map { Result<[TableDTO], Error>.success([=10=]) }
.catchError { Observable.just(Result<[TableDTO], Error>.failure([=10=]) }
}
我在我的项目中使用了 RxSwift 和 Swinject。我绑定输入/输出的方式与 RxSwift 给出的示例不完全相同。在RxExample/GitHubSignup中,绑定是在init()
中完成的,对吗?但是我发现很难实现,因为我使用的是Swinject+SwinjectStoryboard对View Controller做Dependency Injection。因此,init()
不可用,因为实例化视图模型的是 Swinject 容器。那么,除了使用 init()
之外,还有没有办法将视图控制器和视图模型绑定在一起?
我在想我也许可以使用 var
而不是 let
作为输出可观察对象,并制作一个 func bind(observables: [Observable])
或将执行从输入到输入的绑定和转换的东西输出代替。但是因为它们将是 var 而不是 let,这意味着我们似乎被允许在整个代码中更改绑定。不像我们只使用 let 并在 init()
中绑定它们。而且,通过使用函数而不是初始化程序,我必须将依赖项存储到成员变量中。如果我使用初始化程序,我可以只转换 map
或 flatMap
.
我还有一个问题。说,如果我有这个:
class MyViewController: UIViewController {
@IBOutlet weak var refreshButton: UIButton!
@IBOutlet weak var tableView: UITableView!
var viewModel: MyViewModel!
private let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
viewModel = MyViewModel(refreshTap: refreshButton.rx.tap, dataProvider: ApiAdapter().getData)
}
private func setupEvents() {
viewModel.tableDTOs.bind(to: tableView.rx.items(
cellIdentifier: reuseId, cellType: TableViewCell.self)) { _, dto, cell in
cell.fill(with: dto)
}.disposed(by: disposeBag)
}
}
final class MyViewModel {
let tableDTOs: Observable<[TableDTO]>
init(refreshTap: Observable<Void>, dataProvider: () -> Observable<[TableDTO]>) {
tableDTOs = Observable.merge(.just(), refreshTap) //Merge with .just to emit at once for initial values
.flatMapLatest { dataProvider().asDriver() }
}
}
所以在这种情况下,如果dataProvider返回complete
或error
,disposable会被处理掉,对吧?因此场景将无响应,因为 UI 已经解除绑定。知道如何解决这个问题吗?
谢谢。
So, is there a way to bind the view controller and view model together besides using
init()
?
是的。为视图模型提供一个接受输入和 returns 输出的函数。
But because they will be vars and not lets, that means it seems like we are permitted to change the bindings throughout the code.
永远不要让 Observable(或 Subject,或 Observer)成为 var
总是使用 let
函数式响应式编程是一种函数式范例,所以没有变量。
So in this case, if the dataProvider returned complete or error, the disposable will be disposed, right? So the scene will be unresponsive because the UI is already unbound. Any idea how to fix that?
是也不是。如果 dataProvider 发出完成的事件,则不会处理,因为 flatMapLatest
仅在其输入的 all 完成时处理。由于 refreshTap
尚未完成,flatMapLatest
将继续接受来自它的事件并为每个事件调用它的闭包。
如果 dataProvider 发出错误事件,将 处理,因为错误事件会使链短路。但是,由于您在 dataProvider 上使用了 .asDriver()
,因此从闭包返回的驱动程序不可能发出错误事件。你安全了。
阻止错误破坏链的其他方法是使用 .materialize()
或任何 .catchError
运算符。例如:
.flatMapLatest {
dataProvider
.map { Result<[TableDTO], Error>.success([=10=]) }
.catchError { Observable.just(Result<[TableDTO], Error>.failure([=10=]) }
}