如何通过可观察的链视图控制器演示器
How to pass chain view controller presenter with observable
我是 RxSwift 开发的新手,在展示视图控制器时遇到问题。
我的 MainViewController 只是一个 table 视图,我想在我点击列表中的项目时显示详细信息。
我的 DetailViewController 是模态显示的,需要一个 ViewModel 作为输入参数。
我想避免解散 DetailViewController,我认为解散的责任属于呈现视图控制器的人,即解散应该发生在 MainViewController 中。
这是我当前的代码
DetailsViewController
class DetailsViewController: UIViewController {
@IBOutlet weak private var doneButton: Button!
@IBOutlet weak private var label: Label!
let viewModel: DetailsViewModel
private let bag = DisposeBag()
var onComplete: Driver<Void> {
doneButton.rx.tap.take(1).asDriver(onErrorJustReturn: ())
}
override func viewDidLoad() {
super.viewDidLoad()
setup()
bind()
}
private func bind() {
let ouput = viewModel.bind()
ouput.id.drive(idLabel.rx.text)
.disposed(by: bag)
}
}
DetailsViewModel
class DetailsViewModel {
struct Output {
let id: Driver<String>
}
let item: Observable<Item>
init(with vehicle: Observable<Item>) {
self.item = item
}
func bind() -> Output {
let id = item
.map { [=11=].id }
.asDriver(onErrorJustReturn: "Unknown")
return Output(id: id)
}
}
主视图控制器
class MainViewController: UIViewController {
@IBOutlet weak private var tableView: TableView!
private var bag = DisposeBag()
private let viewModel: MainViewModel
private var detailsViewController: DetailsViewController?
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
bind()
}
private func bind() {
let input = MainViewModel.Input(
selectedItem: tableView.rx.modelSelected(Item.self).asObservable()
)
let output = viewModel.bind(input: input)
showItem(output.selectedItem)
}
private func showItem(_ item: Observable<Item>) {
let viewModel = DetailsViewModel(with: vehicle)
detailsViewController = DetailsController(with: viewModel)
item.flatMapFirst { [weak self] item -> Observable<Void> in
guard let self = self,
let detailsViewController = self.detailsViewController else {
return Observable<Void>.never()
}
self.present(detailsViewController, animated: true)
return detailsViewController.onComplete.asObservable()
}
.subscribe(onNext: { [weak self] in
self?.detailsViewController?.dismiss(animated: true)
self?.detailsViewController? = nil
})
.disposed(by: bag)
}
}
MainViewModel
class MainViewModel {
struct Input {
let selectedItem: Observable<Item>
}
struct Output {
let selectedItem: Observable<Item>
}
func bind(input: Input) -> Output {
let selectedItem = input.selectedItem
.throttle(.milliseconds(500),
latest: false,
scheduler: MainScheduler.instance)
.asObservable()
return Output(selectedItem: selectedItem)
}
}
我的问题是 showItem
的 MainViewController。
我仍然认为将 DetailsViewController 输入作为 Observable 是行不通的,但根据我从 Rx 中了解到的情况,我们应该尽可能多地使用 Observable。
使用 Item
而不是 Observable<Item>
作为输入可以让我使用这种代码:
item.flatMapFirst { item -> Observable<Void> in
guard let self = self else {
return Observable<Void>.never()
}
let viewModel = DetailsViewModel(with: item)
self.detailsViewController = DetailsViewController(with: viewModel)
guard let detailsViewController = self.detailsViewController else {
return Observable<Void>.never()
}
present(detailsViewController, animated: true)
return detailsViewController
}
.subscribe(onNext: { [weak self] in
self?.detailsViewController?.dismiss(animated: true)
self?.detailsViewController = nil
})
.disposed(by: bag)
正确的做法是什么?
谢谢
你不应该“尽可能多地使用 Observable”。如果一个对象只需要处理一个项目,那么只需传递该项目即可。例如,如果标签只显示“Hello World”,则只需将字符串分配给标签的文本 属性。不要费心将它包装在 just
中并将其绑定到标签的 rx.text.
你的第二个选项更接近你应该拥有的。这个主意不错。
您可能会发现我的 CLE library 很有趣。它会处理您在此处尝试处理的问题。
我是 RxSwift 开发的新手,在展示视图控制器时遇到问题。
我的 MainViewController 只是一个 table 视图,我想在我点击列表中的项目时显示详细信息。
我的 DetailViewController 是模态显示的,需要一个 ViewModel 作为输入参数。
我想避免解散 DetailViewController,我认为解散的责任属于呈现视图控制器的人,即解散应该发生在 MainViewController 中。
这是我当前的代码
DetailsViewController
class DetailsViewController: UIViewController {
@IBOutlet weak private var doneButton: Button!
@IBOutlet weak private var label: Label!
let viewModel: DetailsViewModel
private let bag = DisposeBag()
var onComplete: Driver<Void> {
doneButton.rx.tap.take(1).asDriver(onErrorJustReturn: ())
}
override func viewDidLoad() {
super.viewDidLoad()
setup()
bind()
}
private func bind() {
let ouput = viewModel.bind()
ouput.id.drive(idLabel.rx.text)
.disposed(by: bag)
}
}
DetailsViewModel
class DetailsViewModel {
struct Output {
let id: Driver<String>
}
let item: Observable<Item>
init(with vehicle: Observable<Item>) {
self.item = item
}
func bind() -> Output {
let id = item
.map { [=11=].id }
.asDriver(onErrorJustReturn: "Unknown")
return Output(id: id)
}
}
主视图控制器
class MainViewController: UIViewController {
@IBOutlet weak private var tableView: TableView!
private var bag = DisposeBag()
private let viewModel: MainViewModel
private var detailsViewController: DetailsViewController?
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
bind()
}
private func bind() {
let input = MainViewModel.Input(
selectedItem: tableView.rx.modelSelected(Item.self).asObservable()
)
let output = viewModel.bind(input: input)
showItem(output.selectedItem)
}
private func showItem(_ item: Observable<Item>) {
let viewModel = DetailsViewModel(with: vehicle)
detailsViewController = DetailsController(with: viewModel)
item.flatMapFirst { [weak self] item -> Observable<Void> in
guard let self = self,
let detailsViewController = self.detailsViewController else {
return Observable<Void>.never()
}
self.present(detailsViewController, animated: true)
return detailsViewController.onComplete.asObservable()
}
.subscribe(onNext: { [weak self] in
self?.detailsViewController?.dismiss(animated: true)
self?.detailsViewController? = nil
})
.disposed(by: bag)
}
}
MainViewModel
class MainViewModel {
struct Input {
let selectedItem: Observable<Item>
}
struct Output {
let selectedItem: Observable<Item>
}
func bind(input: Input) -> Output {
let selectedItem = input.selectedItem
.throttle(.milliseconds(500),
latest: false,
scheduler: MainScheduler.instance)
.asObservable()
return Output(selectedItem: selectedItem)
}
}
我的问题是 showItem
的 MainViewController。
我仍然认为将 DetailsViewController 输入作为 Observable 是行不通的,但根据我从 Rx 中了解到的情况,我们应该尽可能多地使用 Observable。
使用 Item
而不是 Observable<Item>
作为输入可以让我使用这种代码:
item.flatMapFirst { item -> Observable<Void> in
guard let self = self else {
return Observable<Void>.never()
}
let viewModel = DetailsViewModel(with: item)
self.detailsViewController = DetailsViewController(with: viewModel)
guard let detailsViewController = self.detailsViewController else {
return Observable<Void>.never()
}
present(detailsViewController, animated: true)
return detailsViewController
}
.subscribe(onNext: { [weak self] in
self?.detailsViewController?.dismiss(animated: true)
self?.detailsViewController = nil
})
.disposed(by: bag)
正确的做法是什么?
谢谢
你不应该“尽可能多地使用 Observable”。如果一个对象只需要处理一个项目,那么只需传递该项目即可。例如,如果标签只显示“Hello World”,则只需将字符串分配给标签的文本 属性。不要费心将它包装在 just
中并将其绑定到标签的 rx.text.
你的第二个选项更接近你应该拥有的。这个主意不错。
您可能会发现我的 CLE library 很有趣。它会处理您在此处尝试处理的问题。