Reputation: 1867
Assume I have array of Ints:
var items = [1, 2, 3, 4, 5]
and a function that takes Int argument and basing on it sends network request:
func sendRequest(argument: Int) -> Observable<Void> {
// sends network request
...
}
I want to send network requests for each element of items array, but I want to do it sequentially, send next request only once previous one is finished.
My first attempt was something like this:
let observables = items.map{ [weak self] argument in (self?.sendRequest(argument: argument) ?? Observable.empty()) }
let result = Observable.concat(observables)
This approach however sends request simultaneously and only combine the results sequentially.
My second approach:
let items = [1, 2, 3, 4, 5]
var result = Observable.just(Void())
for item in items {
result = result.flatMap{ [weak self] in
self?.sendRequest(argument: item) ?? Observable.empty()
}
}
It seems to work, but obviously result emits next element only once all network requests finish.
What I would need is sending requests sequentially with result observable that emits next event once each single request is finished.
Any suggestions?
Upvotes: 7
Views: 6767
Reputation: 4077
Operator .concatMap()
guarantees that order remains intact, as opposed to .flatMap()
i.e.
Observable.from([1,2,3,4,5]).concatMap( /* your request code */ )
UPDATE
let source = Observable.from([1,2,3,4,5])
let trigger = BehaviorSubject<Int>(value: 0)
let feed = Observable.zip(source, trigger) { return $0.0 }
feed.concatMap {
/* your request code */
trigger.onNext(0) // possibly in .onComplete of the service call
}
Upvotes: 3