Как с помощью оператора RxSwift выбрать сразу все элементы?

Допустим, у меня есть табличное представление продуктов.

Вот моя модель просмотра:

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 { $0.count },
            envelope.map { $0.products.count })
        .debug()
        .map { $0.0 == $0.1 }

Как видите, каждый раз, когда я выбираю объект, я переводю его в состояние observable, чтобы затем ячейка могла наблюдать за изменением состояния.

Вот привязка RxSwift между ячейкой и viewModel:

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 { $0.contains(item) }
    .drive(self.rx.isSelected)
    .disposed(by: rx.reuseBag)
}

Что ж, пока все хорошо.

Теперь мой вопрос: как я могу выбрать все действие, например. нажатие кнопки «Выбрать все», чтобы все продукты каким-то образом были scan в состояниях?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
367
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Конечно, есть и другие способы сделать это. Мне на ум приходит два разных события для 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())

Надеюсь, это поможет.

Такой умный! Спасибо.

Zigii Wong 17.03.2018 16:37

Другие вопросы по теме