Допустим, у меня есть табличное представление продуктов.
Вот моя модель просмотра:
var selectedObserver: AnyObserver<Product>
var state: Driver<Set<Product>>
var selectedSubject = PublishSubject<Product>()
self.selectedObserver = selectedSubject.asObserver()
self.state =
selectedSubject.asObservable()
.scan(Set()) { (acc: Set<Product>, item: Product) in
var acc = acc
if acc.contains(item) {
acc.remove(item)
} else {
acc.insert(item)
}
return acc
}
.startWith(Set())
.asDriver(onErrorJustReturn: Set())
self.isSelectedAll = Driver
.combineLatest(
self.state.map { $0.count },
envelope.map { $0.products.count })
.debug()
.map { $0.0 == $0.1 }
Как видите, каждый раз, когда я выбираю объект, я переводю его в состояние observable, чтобы затем ячейка могла наблюдать за изменением состояния.
Вот привязка RxSwift между ячейкой и viewModel:
self.viewModel.deliveries
.drive(self.tableView.rx.items(cellIdentifier: DeliveryTableViewCellReusableIdentifier, cellType: DeliveryTableViewCell.self)) { (_, item, cell) in
cell.bind(to: self.viewModel.state, as: item)
cell.configureWith(product: item)
}
.disposed(by: disposeBag)
self.tableView.rx.modelSelected(Product.self)
.asDriver()
.drive(self.viewModel.selectedObserver)
.disposed(by: disposeBag)
func bind(to state: Driver<Set<Product>>, as item: Product) {
state.map { $0.contains(item) }
.drive(self.rx.isSelected)
.disposed(by: rx.reuseBag)
}
Что ж, пока все хорошо.
Теперь мой вопрос: как я могу выбрать все действие, например. нажатие кнопки «Выбрать все», чтобы все продукты каким-то образом были scan в состояниях?





Конечно, есть и другие способы сделать это. Мне на ум приходит два разных события для single selection и select all, объединяющих их в одно перечисление, например. SelectionEvent, объединяя их и передавая на scan, чтобы в методе сканирования вы могли различать их.
Грубый пример, следующий за вашим кодом:
var selectedObserver: AnyObserver<Product>
var state: Driver<Set<Product>>
var selectedSubject = PublishSubject<Product>()
var selectedAllSubject = PublishSubject<Product>() // Added
var selectedAllObserverObserver: AnyObserver<Void> // Added
self.selectedObserver = selectedSubject.asObserver()
self.selectedAllObserverObserver = selectedAllSubject.asObserver()
enum SelectionEvent {
case product(Product)
case all([Product])
}
self.state = Observable.of(
selectedSubject.map { SelectionEvent.product($0) },
// I figured envelope is observable containing all products.
selectedAllSubject.withLatestFrom(envelope.map { $0.products }).map { SelectionEvent.all($0) }
).merge()
.scan(Set()) { (acc: Set<Product>, event: SelectionEvent) in
var acc = acc
// now you can differentitate between events
switch event {
case .product:
if acc.contains(item) {
acc.remove(item)
} else {
acc.insert(item)
}
case .all(let all):
acc = all
}
return acc
}
.startWith(Set())
.asDriver(onErrorJustReturn: Set())
Надеюсь, это поможет.
Такой умный! Спасибо.