dobranoc
dobranoc

Reputation: 475

RxSwift — background task without freezing UI

I would like to do some heavy lifting in the background thread of my iOS app and NOT freeze the UI while it is being performed. What I try is:

self.someDisposable = heavyLiftingFuncReturningObservable()
            .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
            .observeOn(MainScheduler.instance)
            .subscribe(
                onNext: { [weak self] image in
                    // update UI
                },
                onError: { ... }
            )

Why does the above not work as expected and how to make it work?

Upvotes: 10

Views: 10861

Answers (3)

user14048314
user14048314

Reputation:

Don't do this... use the Observable.deferred { } method

Put the heavy task inside the block and it will run on subscription.

If the work has a single response, use a Single observable type.
If the work only has to complete, use a Completable observable type

Use the observeOn / subscribleOn operators to control the thread doing the work.

Best of all, don't use RX for this use case.

Upvotes: 0

SoftDesigner
SoftDesigner

Reputation: 5854

You can do this:

self.someDisposable = Observable.just(0) // dummy
    .observeOn(ConcurrentDispatchQueueScheduler(qos: .background))
    .flatMap { [unowned self] _ in
        heavyLiftingFuncReturningObservable()
    }
    .observeOn(MainScheduler.instance)
    .subscribe(
        onNext: { [weak self] image in
            // update UI
        },
        onError: { ... }
    )

Upvotes: 5

Maxim Volgin
Maxim Volgin

Reputation: 4077

I believe the problem lies in your implementation of .heavyLiftingFuncReturningObservable(), namely in the fact that apparently it starts working on current thread instead of waiting until being subscribed to and running on background scheduler. Solution for that is to use .deferred() inside of .heavyLiftingFuncReturningObservable() function.

See http://adamborek.com/top-7-rxswift-mistakes/

Upvotes: 7

Related Questions