RxSwift观察数组的变化

时间:2018-07-04 16:05:03

标签: ios swift rx-swift rx-cocoa

假设我们有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 :(得分:1)

entityisSelected变量需要是let而不是vars。

这是我想出的解决方案:

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内部删除变量。

答案 1 :(得分:0)

首先,请注意,RxCocoa中不推荐使用Variable(改为使用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(),否则您将看到很多发出的元素。)