可观察的当前和先前价值

时间:2016-03-17 02:00:39

标签: swift rx-swift

我有一个变量,它是一个枚举值数组。这些值随时间而变化。

enum Option {
    case One
    case Two
    case Three
}

let options = Variable<[Option]>([ .One, .Two, .Three ])

然后我观察这个变量的变化。问题是,我需要知道最新值和前一个值之间的差异。我现在正在这样做:

let previousOptions: [Option] = [ .One, .Two, .Three ]

...

options
    .asObservable()
    .subscribeNext { [unowned self] opts in
        // Do some work diff'ing previousOptions and opt
        // ....
        self.previousOptions = opts
    }

RxSwift内置了哪些内容可以更好地管理它?有没有办法总是从信号中获取先前值和当前值?

7 个答案:

答案 0 :(得分:16)

这是一个方便的通用扩展,应该涵盖这些“我想要前一个和当前值”用例:

extension ObservableType {

    func withPrevious(startWith first: E) -> Observable<(E, E)> {
        return scan((first, first)) { ($0.1, $1) }.skip(1)
    }
}

答案 1 :(得分:9)

你去了

docker run-it --privileged -v /dev/bus/usb:/dev/bus/usb -v (shared directory path):(path in container) debian:latest bash

它将返回options.asObservable() .scan( [ [],[] ] ) { seed, newValue in return [ seed[1], newValue ] } // optional, working with tuple of array is better than array of array .map { array in (array[0], array[1]) } //optional, in case you dont want empty array .skipWhile { $0.count == 0 && $1.count == 0 } :)

答案 2 :(得分:5)

正如Pham Hoan所说,scan(_)是适合这项工作的工具。 Marin Todorov写了一篇good post来做这件事。

根据马林的帖子,我提出了以下内容:

options
        .asObservable()
        .scan([]) {
            (previous, current) in
                return Array(previous + [current]).suffix(2)
        }
        .subscribeNext {
            (lastTwoOptions) in
                let previousOptions = lastTwoOptions.first
                let currentOptions = lastTwoOptions.last
                // Do your thing.  Remember to check for nil the first time around!
        }
        .addDisposableTo(self.disposeBag)

希望有所帮助

答案 3 :(得分:1)

我会建议这样的事情(对于未来的访客):

options.asObservable()
       .map { (old: [], new: $0) }   // change type from array to tuple
       .scan((old: [], new: [])) { previous, current in
           // seed with an empty tuple & return both information
           return (old: previous.new, new: current.new)
       }
       .subscribe(onNext: { option in
           let oldArray = option.old   // old
           let newArray = option.new   // new
       }
       .addDisposableTo(disposeBag)

答案 4 :(得分:1)

一行中的最佳解决方案:

Observable.zip(options, options.skip(1))

答案 5 :(得分:1)

.pairwise()运算符完全可以完成您想要的操作,并且是执行此操作的最简单方法。该运算符将成对的连续发射分组在一起,并以两个值的数组形式发射它们。

请参阅:http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-pairwise

https://rxjs-dev.firebaseapp.com/api/operators/pairwise


更新:正如@courteouselk在他的评论中指出的那样,我没有注意到这是一个RxSwift问题,并且我的答案引用了一个RxJS解决方案(糟糕!)。

结果证明RxSwift没有内置pairwise运算符,但是RxSwiftExt提供了pairwise扩展运算符,类似于内置RxJS运算符

答案 6 :(得分:0)

另一种扩展方式

extension ObservableType {

  func withPrevious() -> Observable<(E?, E)> {
    return scan([], accumulator: { (previous, current) in
        Array(previous + [current]).suffix(2)
      })
      .map({ (arr) -> (previous: E?, current: E) in
        (arr.count > 1 ? arr.first : nil, arr.last!)
      })
  }
}

用法:

someValue
  .withPrevious()
  .subscribe(onNext: { (previous, current) in
    if let previous = previous { // previous is optional
      print("previous: \(previous)")
    }
    print("current: \(current)")
  })
  .disposed(by: disposeBag)