J'ai une variable qui est un tableau de valeurs énumérées. Ces valeurs changent avec le temps.
enum Option {
case One
case Two
case Three
}
let options = Variable<[Option]>([ .One, .Two, .Three ])
J'observe ensuite cette variable pour les changements. Le problème est que j'ai besoin de connaître la différence entre la valeur la plus récente et la valeur précédente. Je fais actuellement ceci:
let previousOptions: [Option] = [ .One, .Two, .Three ]
...
options
.asObservable()
.subscribeNext { [unowned self] opts in
// Do some work diff'ing previousOptions and opt
// ....
self.previousOptions = opts
}
Y a-t-il quelque chose de intégré à RxSwift qui pourrait mieux gérer cela? Existe-t-il un moyen d'obtenir toujours les valeurs précédentes et actuelles d'un signal?
voilà
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 }
il renverra Observable<([Options], [Options])>
:)
Voici une extension générique pratique, qui devrait couvrir ces "Je veux la valeur précédente et la valeur actuelle" cas d'utilisation:
extension ObservableType {
func withPrevious(startWith first: E) -> Observable<(E, E)> {
return scan((first, first)) { ($0.1, $1) }.skip(1)
}
}
Comme l'a dit Pham Hoan, scan(_)
est le bon outil pour le travail. Marin Todorov a écrit un bon article pour faire exactement cela.
Voici ce que j'ai trouvé, basé sur le post de Marin:
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)
J'espère que cela pourra aider
Une autre façon comme extension
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!)
})
}
}
Usage:
someValue
.withPrevious()
.subscribe(onNext: { (previous, current) in
if let previous = previous { // previous is optional
print("previous: \(previous)")
}
print("current: \(current)")
})
.disposed(by: disposeBag)
Meilleure solution en une seule ligne:
Observable.Zip(options, options.skip(1))
Je suggérerais quelque chose comme ça (pour les futurs visiteurs):
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)
L'opérateur .pairwise()
fait exactement ce que vous voulez et est le moyen le plus simple de le faire. Cet opérateur regroupe des paires d'émissions consécutives et les émet sous la forme d'un tableau de deux valeurs.
voir: http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-pairwise
ou https://rxjs-dev.firebaseapp.com/api/operators/pairwise
MISE À JOUR: comme @courteouselk l'a souligné dans son commentaire, je n'ai pas remarqué qu'il s'agissait d'une question RxSwift, et ma réponse faisait référence à une solution RxJS (oups!).
Il s'avère que RxSwift n'a pas un opérateur pairwise
intégré, mais RxSwiftExt fournit un par paire opérateur d'extension similaire à l'opérateur RxJS intégré.