RxSwift Quick Overview

In yesterday’s post, we walked through how one could take “Enumerable”, (or, really, Sequence) and “Enumerator” (really, Iterator), and turn them into Observable and Observer. These are the two types that underpin most everything in RxSwift.

In this post, let’s explore a little more about what RxSwift is, and what it isn’t.

Let’s Make a Sandwich

When people colloquially refer to “RxSwift”, they’re often referring to an entire group of projects and technologies. When writing an iOS app, it is certainly possible to use only RxSwift, but that’s like making a sandwich only of bread.

In reality, the beauty of RxSwift from an app developer’s perspective is not the RxSwift “bread”, but rather the meats and condiments inside. More directly, RxSwift is fine, but interaction with things like user interfaces and system frameworks is what makes RxSwift really shine.

One of my favorite uses of RxSwift is to interact with user interfaces. The taps of a UIButton are an excellent example of something that can be exposed as an Observable.

However, using only RxSwift, there isn’t a terribly straightforward way to expose a button tap as an Observable. It’s certainly doable, but would require creating an entire object just to be the receiver of the button’s .touchUpInside action. That’s a lot of housekeeping to get to one button’s tap.

Thankfully, many of these menial tasks are already taken care of. Instead of having to worry about writing an entire object to worry about a button tap, you can leverage a project that’s built upon RxSwift.

RxCocoa

RxCocoa is sort of part of RxSwift, though it’s sort of not. It’s a separate target, and must be imported on its own, but the source lives within the RxSwift repository.

It’s RxCocoa that brings all of these convenient bindings to the table. Thus, instead of having to do a whole bunch of housekeeping in order to get to a button tap, one can just do this:

let disposeBag = DisposeBag()
let button = UIButton()
button.rx.tap
    .subscribe(onNext: { _ in
        print("Tap!")
    })
    .disposed(by: disposeBag)

That is so nice, and so convenient.

Furthermore, there are equivalent bindings for mostly anything an average iOS developer runs into in a normal application. RxCocoa has bindings for UITabBar's selectedItem. For UIProgressView’s progress. For UITextField's text. The list goes on and on and on.

Let’s Join a [RxSwift]Community

RxCocoa can’t be all things to all people, though. However, the beauty of open-source is that others can join in, help, and share their code.

Enter RxSwiftCommunity.

RxSwiftCommunity is, naturally, a community-led project to extend RxSwift and RxCocoa to cover what those projects do not. A phenomenal example of this, that I’ve used in Vignette, is RxGesture. RxGesture exposes many gesture-based events by way of Observables. For example:

let someView = UIView()
let observable: Observable<UITapGestureRecognizer> = 
    someView.rx.tapGesture { (recognizer, _) in
        recognizer.numberOfTapsRequired = 3
    }
    .when(.recognized)

Just like before, it’s certainly possible to do this by hand, but it is so much nicer to be able to just grab an open-source solution to do it for you. An open-source solution that has been used many many times, and thus is far better tested than any bespoke solution would be.

Furthermore, there are a ton of RxSwiftCommunity projects. To call out just a few:

Finally, newest and perhaps most interestingly:

  • RxCombine
    Currently empty, but perhaps an attempt at an RxSwift ↔ Combine bridge?

Speaking of Testing

Another incredible feature of RxSwift, and peer to RxCocoa, is RxTest. RxTest is a wonderful suite of tools that allows you to easily test code based on Observables. This includes simulating events on a stream, at precise virtual times, in order to observe their results on the system.

I cover a lot of RxTest in my fifth and final RxSwift Primer post. Suffice it to say, RxTest makes it [almost] enjoyable to write unit tests for RxSwift-based code.

All Together Now

RxSwift in and of itself is impressive, but it is an empty sandwich. While it may be made of the most delicious bread known to man, it’s still just bread. Without the meat that is RxCocoa, the cheese that is RxCommunity, and the condiments that are RxTest, it’s just not the same.

Next week, I’ll spend some time comparing the API surface area of Combine to that of RxSwift, as well as discuss some core differences in the design of the two projects.