RxSwift наблюдает за изменениями в массиве - PullRequest
0 голосов
/ 04 июля 2018

Допустим, у нас есть массив InvoiceDataModel

private let invoices Variable<[InvoiceDataModel]> = Variable([])

class InvoiceDataModel { 
    let id: Variable<Int>
    var entity: Variable<InvoiceDto>
    var isSelected: Variable<Bool> 
}

При нажатии на флажок я изменяю значение isSelected. Чего я хочу добиться, так это реагировать на изменения isSelect следующим образом:

  • подсчитать общее количество выбранных предметов (у каждого объекта есть var amount: Double)
  • определить, выбраны ли все элементы в коллекции

Можно ли наблюдать за всем массивом и реагировать на одно свойство при изменении элемента? Не уверен, как мне этого добиться.

Возможно, мой подход к этому делу совершенно неверен. Однако я не уверен, как мне действовать здесь по-другому.

Ответы [ 2 ]

0 голосов
/ 23 ноября 2018

Переменные entity и isSelected должны быть разрешены, а не переменными.

Вот решение, которое я придумал:

let selectedsAndAmounts = invoices
    .asObservable()
    .flatMapLatest {
        Observable.combineLatest($0.map {
            Observable.combineLatest($0.isSelected.asObservable(), Observable.just($0.amount)) { (isSelected: $0, amount: $1) }
        })
    }

let allSelected = selectedsAndAmounts
    .map { $0.map { $0.isSelected } }
    .map { $0.contains(false) == false }

let amountOfSelected = selectedsAndAmounts
    .map { $0.map { $0.isSelected ? $0.amount : 0 } }
    .map { $0.reduce(0, +) }

Большая часть сложности в этом решении (наблюдаемая selectedsAndAmounts) связана с необходимостью развертывания наблюдаемых внутри наблюдаемых. Было бы лучше, если бы вы могли немного разбить это или удалить переменные из InvoiceDataModel.

0 голосов
/ 09 августа 2018

Прежде всего, обратите внимание, что переменная устарела в RxCocoa (используйте вместо нее BehaviorRelay).

Краткое решение состоит в том, чтобы объединить isSelected наблюдаемые в одну наблюдаемую эмиссию количества. Я просто бросил этот фрагмент вместе, но он должен указать вам правильное направление.

invoices
    // whenever the list changes, subscribe to the combined observable (and dispose of any previous subscriptions)
    .flatMapLatest { list in
        // merge all isSelected observables together
        return Observable.merge(list.map { $0.isSelected })
    }
    // when an element is emitted, that means some `isSelected` observable has changed its value
    // get the latest invoices array 
    .withLatestFrom(invoices)
    // convert it from a InvoiceDataModel array to a summed amount of all elements
    .map { $0.reduce(0) { $0 + $1.amount } }
    // log all events passing through
    .debug()
    .subscribe()
    .disposed(by: yourDisposeBag)

Вы можете использовать аналогичный подход для подписки на Observable, который генерируется, если выбраны все элементы. (Не забудьте о .distinctUntilChanged(), иначе вы увидите много испускаемых элементов.)

...