Wujo
Wujo

Reputation: 1867

RxSwift - how to chain observables sequentially

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

Answers (1)

Maxim Volgin
Maxim Volgin

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

Related Questions