Skip to Content

Reactive Swift: Progress HUD Extension and Order of Events

A blocking progress HUD to show a network or any other asynchronous activity may not be the most elegant solution, but sometimes it just gets the job done. Using ReactiveSwift you can use a SignalProducer extension to quickly show & hide a HUD for any reactive operation:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
extension SignalProducer {

    public func bindToProgressHUD(_ viewDelay: Double = 0.3, showSuccess: Bool = false) -> SignalProducer<Value, Error> {
        return on(started: {
            HUD.show(.progress)
        }, failed: { _ in
            HUD.flash(.error, delay: viewDelay)
        }, completed: {
            if showSuccess {
                HUD.flash(.success, delay: viewDelay)
            } else {
                HUD.hide()
            }
        }, interrupted: {
            HUD.flash(.error, delay: viewDelay)
        })
    }
}

Hint: you can use a similar extensions to alert the user of any error or log network requests for debugging purposes.

However, recently I stumpled upon a strange behaviour in a project: the HUD would show, but never hide, even though the network request completed successfully. This is always my worst nightmare when using any blocking UI elements. There is nothing the user can do than kill the app.

The problem occurred after I added caching to several requests, and after investigating I found out that the problem only occurs if the request is served from the cache where I used SignalProducer(value: myCachedResponse) to return the response. Printing out the events of on() I noticed a strange order:

1
2
3
4
starting
value
completed
started

🤯 Not really what I was expecting. Turns out, it is the expected behaviour though (see https://github.com/ReactiveCocoa/ReactiveSwift/issues/115) as the SignalProducer completes before it is started. Still weird and not really well documented at all (unfortunately, like so many other ReactiveSwift things). Knowing this oddity, I simply changed my code to show the HUD on starting instead of started.