5 min read

How many times should queries really be performed? Let’s discuss what the right amount of querying is.To keep things simple initially, the constraints that we want to have are the following: 

  1. It must display the queue information when we view the view controller.
  2. It needs to refresh the queue when we press a button from the view controller. 

Because we are assuming that the Observables we were working with are wrapped with the Observable.create() method as defined here, they are inherently cold observables, and cold observables only perform the observable code once, which is on subscription. 

We are also defining and wrapping the network call into a reliable Observable<[Queue]>, but what we need is to have this network call performed when the button is tapped. 

Introducing Subjects

The desired behavior of the UITableView is to not simply “observe” the present state of the queue data (i.e. the behavior of a cold observable, which is to only have 1 emission or usually contain 1 element, and in our case, it is the current state of the queue);we want it to be reactive. We want it to change whenever we press a button and the data changes from the server. 

We can do this by using hot observables in the form of subjects. Take this time to browse briefly through the Reactivex documentation; a brief snippet of its description is shown below: 

“Because a Subject subscribes to an Observable, it will trigger that Observable to begin emitting items (if that Observable is “cold”, that is, if it waits for a subscription before it begins to emit items). This can have the effect of making the resulting Subject a “hot” Observable variant of the original “cold” Observable.”

Because a subject is both an observer and an observable, we can use it to subscribe to an observable. We can actually come up with this implementation: 

privatevar queues = BehaviorSubject<[Queue]>(value: [])
privatevardisposeBag = DisposeBag()

funconButtonPress() {
getQueue()
            .subscribeOn(ConcurrentDispatchQueueScheduler(queue: networkQueue))
            .observeOn(MainScheduler.instance)
            .subscribe(queues.asObserver())
            .addDisposableTo(disposeBag)
    }

The onButtonPress() method can even be called in viewDidLoad to load the first set of data. Now hook that up to an IBOutlet;pressing the button now works to query the data from the server! 

Great! Are we done? 

Not quite. A problem that might arise is that your users may become impatient while you load your data. What happens when they click the button repeatedly? 

By doing so, the user will have created subscriptions as many times as they have impatiently clicked the button. This is not how we want our code to work. 

You can look into operators such as flatMapLatest, which ignores the previous subscription if there is a new subscription. You might get pointed to the throttle or debounce operator, which only emits an item from an Observable if a particular timespan has passed without it emitting another item. But we don’t expect our average users to tap like crazy, but this is where you begin to explore the other operators. 

A quick UI fix might be to present an alert telling the users that the data is being loaded (and praying that the data is loaded faster than the user can close the alert and click the button again), but personally, I believe itdoesn’t provide a great user experience. 

I personally prefer a balance of flatMapLatest so that old subscriptions are ignored. It is ignored with an additional UI tweak of disabling the user interface by overlaying a UIView so that the user is informed that the data is loading and so that the button temporarily doesn’t recognize taps. 

Pushing further; more reactive 

If you want your app to be even more reactive, you can replace the trigger (the button press) with somethingelse! 

You want it to poll data every 5 minutes? Use a timer! 

You can even hook up your BehaviorSubject to some kind of synchronization library or use WebSocket technology so that when your server informs you that data has changed, your app responds in real time! 

Tread carefully, because you need to think about synchronization issues and thread safety here. 

But why do we use a BehaviorSubject? Why not a different kind of Subject or a Variable?

Reactivex describes BehaviorSubject below: 

“When an observer subscribes to a BehaviorSubject, it begins by emitting the item most recently emitted by the source Observable (or a seed/default value if none has yet been emitted), and then continues to emit any other items emitted later by the source Observable(s).” 

In the same way, we want our UITableView to be able to provide something when the UITableView subscribes to it. We can seed it initially with an empty array of Queue, and then later, load the data from the database or from a network query. 

Dealing with the abstract 

Hopefully, this two-part series has enlightened and encouraged you in your professional journey in learning the benefits of functional reactive programming that RxSwift provides. My personal take on it is that the Reactive Extensions arequite difficult to grasp because they are abstract. Theabstraction allows more experienced programmers to use the appropriate tools when deemed fit. 

I hope that this series has brought the beautiful abstract definitions into a more concrete example and that it has been a gentle introduction to what hot and cold observables are, what subjects are, and how to use them. I framed them with simple assumptions that are quite common in real-life situations within the context of application development to make it much more relatable and concrete.

About the Author

Darren Karl Sapalo is a software developer, an advocate for UX, and a student taking up his Master’s degree in Computer Science. He enjoyed developing games on his free time when he was twelve. Finally finished with his undergraduate thesis on computer vision, he took up some industry work with Apollo Technologies Inc., developing for both Android and iOS platforms. 

LEAVE A REPLY

Please enter your comment!
Please enter your name here