RxSwifty and the Secret of the Variadic DisposeBag
Use one of RxSwift’s newest features to dramatically clean up your code
My company has been using RxSwift for all new iOS projects for a while now, and we’ve come to appreciate it’s power, flexibility, and conciseness.
That said, there is one area where RxSwift is, shall we say, somewhat less than concise. Where, in point of fact, it’s downright redundant.
So today, let’s talk about Disposables and DisposeBags.
Disposables and DisposeBags?
As I’m sure you’re aware, Disposables and DisposeBags are RxSwift’s concession to Swift’s ARC memory management.
When you subscribe or bind to or drive from a RxSwift Observable, that subscription returns a Disposable. That disposable is basically a reference to that subscription and to that subscription’s entire Observable chain.
Until that disposable is disposed, the subscription chain exists (unless the subscription receives a completed or error event, but that’s another story).
So. Bottom line is that subscriptions return disposables which we need to maintain in order to properly control the lifecycle of the subscription.
Those disposables, for the sake of convenience, are usually inserted into a DisposeBag that’s been created and attached to a UIViewController (or in some cases to a View Model or other object).
And a DisposeBag is exactly what it says it is, a bag (or collection) of disposables.
So how does that help us?
Well, when the view controller is deallocated, its variables (including the bag) are deallocated. When the disposeBag is deallocated, its deinit function calls dispose on all of the disposables it contains.
Those disposables, in turn, release any references they may have to any observables they’re observing which may also, in turn, release their references to their observables, and so on, and so on, up the chain until we’re done.
Everything is properly released, nothing has leaked, and everyone is happy.
Except for one minor problem.
So, let’s say you’re using RxSwift and that you’re using a MVVM (Model-View-ViewModel) architecture.
On this particular screen our view model is exposing a set of observables, and our view controller is binding those observables to a set of labels. Pretty basic stuff.
The code looks like this.
It’s all very straightforward, but perhaps you’ve noticed a slight bit of redundant, boilerplate code in the above example?
That’s right. Each and every subscription (bind) returns a disposable that has to be added to the disposeBag. Each one returns it. And each one has to be maintained. There’s no getting around it.
Or is there?
Solution? The Variadic DisposeBag
Now check out the following code.
Much cleaner! But what happened to all of the disposables?
Well, RxSwift 4.3 added a variadic version of the DisposeBag’s insert function. And variadic functions can take one — or more — parameters. In this case one or more disposables.
Because if you look inside disposed(by: disposeBag), you’ll find that it’s just one line of code: disposeBag.insert(self).
So instead of taking the result of each subscription and functionally chaining it to disposed(by:), we just bypass the middleman and add each one directly to the disposeBag ourselves.
I think you’ll agree that the code is definitely more concise and that by eliminating some of the boilerplate we can better express the intent of the function.
By the way, if you find the variadic insert on DisposeBag useful, you’re welcome. It was one of my minor contributions to the RxSwift project. ;)