Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sequentially and nonparallel loop through an array in RxSwift?

Tags:

rx-swift

I have a list of objects i need to send to a server and i would like to do this one after the other (not in parallel). After all objects have been sent and there was no error i want to run additional Observables which do different things.

let objects = [1, 2, 3]

let _ = Observable.from(objects).flatMap { object -> Observable<Void> in
    return Observable.create { observer in
        print("Starting request \(object)")
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) { // one request takes ~2sec
            print("Request \(object) finished")
            observer.onNext(Void())
            observer.onCompleted()
        }
        return Disposables.create()
    }
}.flatMap { result -> Observable<Void> in
    print("Do something else (but only once)")
    return Observable.just(Void())
}.subscribe(
    onNext: {
        print("Next")
    },
    onCompleted: {
        print("Done")
    }
)

What i get is

Starting request 1
Starting request 2
Starting request 3
Request 1 finished
Do something else (but only once)
Next
Request 2 finished
Do something else (but only once)
Next
Request 3 finished
Do something else (but only once)
Next
Done

The whole process ends after 2 sec. What i want is

Starting request 1
Request 1 finished
Starting request 2
Request 2 finished
Starting request 3
Request 3 finished
Do something else (but only once)
Next
Done

The whole sequence should end after 6 seconds (because it's not executed parallel).

I got this to work with a recursive function. But with lots of requests this ends in a deep recursion stack which i would like to avoid.

like image 585
Florian L. Avatar asked Mar 01 '26 06:03

Florian L.


1 Answers

Use concatMap instead of flatMap in order to send them one at a time instead of all at once. Learn more here:

RxSwift’s Many Faces of FlatMap

Then to do something just once afterwards, use toArray(). Here is a complete example:

let objects = [1, 2, 3]

_ = Observable.from(objects)
    .concatMap { object -> Observable<Void> in
        return Observable.just(())
            .debug("Starting Request \(object)")
            .delay(.seconds(2), scheduler: MainScheduler.instance)
            .debug("Request \(object) finished")
    }
    .toArray()
    .flatMap { results -> Single<Void> in
        print("Do something else (but only once)")
        return Single.just(())
    }
    .subscribe(
        onSuccess: { print("done") },
        onError: { print("error", $0) }
    )
like image 119
Daniel T. Avatar answered Mar 06 '26 13:03

Daniel T.



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!