如何使用 RxSwift 运算符一次 select 所有项目?

How can I select all item at once using RxSwift operator?

假设我有 table 展示产品的观点。

这是我的视图模型:

ProductViewModel.swift

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 { [=11=].count },
            envelope.map { [=11=].products.count })
        .debug()
        .map { [=11=].0 == [=11=].1 }

如你所见,每次我select一个对象,我都会scan它进入状态可观察,这样细胞就可以观察到状态变化。

这是 cell 和 viewModel 之间的 RxSwift 绑定:

ProductViewController.swift

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)

ProductCell.swift

func bind(to state: Driver<Set<Product>>, as item: Product) {
    state.map { [=13=].contains(item) }
    .drive(self.rx.isSelected)
    .disposed(by: rx.reuseBag)
}

嗯,到目前为止一切顺利。

现在我的问题是如何进行 select 全部操作,例如点击 select 全部按钮,以便所有产品都以某种方式 scan 进入状态?

当然,还有更多方法可以做到这一点。我想到的一个是 single selectionselect 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([=10=]) },
            // I figured envelope is observable containing all products.
            selectedAllSubject.withLatestFrom(envelope.map { [=10=].products }).map { SelectionEvent.all([=10=]) }
        ).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())

希望对您有所帮助。