我有一个从视图模型中的shiftCells
数组填充的表。渲染了约8种不同类型的单元格,我需要根据单击的单元格对每个单元格执行不同的操作。我试图找出在视图模型中处理此问题的最佳方法,以便视图控制器仅关心最终结果(以便它可以导航到新的视图控制器,等等。),但是努力寻找一种适当地组织它的方法。这是我当前的tableview点击绑定在VC中的样子:
shiftsTableViewController
.cellSelection
.subscribe(onNext: { [weak self] (cellType: ShiftSelectionsTableViewCellType) in
guard let sSelf = self else { return }
switch cellType {
case .cellTypeA(let viewModel):
self.performSomeAction(viewModel: viewModel)
...etc...
}
}).disposed(by: disposeBag)
根据单元格的类型,我执行一个自定义操作(它可能是一个网络请求,其结果将进入导航到的新VC,或者可能是其他东西)。 performSomeAction
如下所示:
func performSomeAction(viewModel: ShiftTypeCellViewModel) {
self.networkService
.perform(
shiftId: viewModel.shiftId, // notice i need data from cell vm
pin: self.viewModel.pin, // i also need data from root vm
photoURL: self.viewModel.imageURL)
.subscribe(onNext: { result in
self.navigateToPage(result: result)
}, onError: { error in
// show error banner
}).disposed(by: disposeBag)
}
因此,在〜8种不同类型的单元格中,我有8种方法,它们的处理方式略有不同。我应该将这些方法移到虚拟机中吗?我是否应该将此方法移到单元VM中并直接在单元视图中处理click事件?忠告/一个例子,将不胜感激。
答案 0 :(得分:1)
您的viewController应该只处理带有单元格选择的UI,然后您的视图模型应该是数据的辅助者。另外,如果可能的话,我会尽量避免让您的单元具有UI代码以外的内容。
// ViewController
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
viewModel.performSomeAction(indexPath: indexPath)
}
func setupObservables() {
viewModel.outputs.reloadRelay
.subscribeOn(MainScheduler.instance)
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] _ in
guard let uwSelf = self else { return }
uwSelf.tableView.reloadData()
}).disposed(by: disposeBag)
}
// ViewModel
// This BehaviorRelay is kinda silly but i'm and trying to demonstrate a trigger that your viewcontroller can listen for to update your UI
var reloadRelay: BehaviorRelay<Bool> = BehaviorRelay(value: false)
func performSomeAction(indexPath: IndexPath) {
switch (indexPath.section, indexPath.row) {
case (1, _):
// Make a network call then update your data
service.randomCall(id: id)
.subscribeOn(MainScheduler.instance)
.subscribe(onNext: { result in
// Update data with result response data
self.navigateToPage(result: result)
}, onError: { [weak self] error in
print(error)
}).disposed(by: disposeBag)
case (2, _):
// Update your data then reload the table
reloadRelay.accept(true)
case (3, _):
// Do something else
case (4, 0):
// Do something else
...
default: break
})
}
答案 1 :(得分:1)
根据您在问题中提供的内容,以下是我想得出的结论:
在VC的viewDidLoad中:
let result = viewModel.generateRequest(forCell: tableView.rx.modelSelected(ShiftSelectionsTableViewCellType.self).asObservable())
.flatMapLatest { [networkService] arg in
(networkService?.perform(shitId: arg.shiftId, pin: arg.pin, photoURL: arg.photoURL) ?? .empty())
.materialize()
}
.share(replay: 1)
result.compactMap { $0.element }
.bind(onNext: { [weak self] result in
self?.navigateToPage(result: result)
})
.disposed(by: disposeBag)
result.compactMap { $0.error }
.bind(onNext: { error in
// show error banner
})
.disposed(by: disposeBag)
在ViewModel中:
func generateRequest(forCell cell: Observable<ShiftSelectionsTableViewCellType>) -> Observable<(shiftId: String, pin: String, photoURL: URL)> {
return cell.map { [pin, imageURL] cellType in
switch cellType {
case .cellTypeA(let viewModel):
return (shiftId: viewModel.shiftId, pin: pin, photoURL: imageURL)
}
// etc...
}
}
这样,所有副作用都在VC中,所有逻辑都在VM中。上面将networkService
放入VC中,因为它是一个副作用对象。