RxSwift and the awesome things you can do with Reactive Programming — Part I

Kenza Iraki
6 min readNov 20, 2016

--

The first time I heard of reactive programming, this is kind of what I looked like:

The second, third and fourth time weren’t much different either. And don’t even get me started on the first time I worked on a project that had some reactive code… that expression was stuck on my face for a full two weeks!

Now I know that there are plenty of people who felt the same way I did when they first encountered reactive programming. I also know a lot of people who, after that first bad impression, never bothered to look into it again, because it sounded like too much effort to even just get started. But what I can tell you for a fact is that I don’t know a single person who, after finally understanding how it works, ever regretted getting into reactive programming.

Now I know there are more than enough resources online dealing with the theory and the intricacies of reactive and RxSwift, there are also plenty of tutorials on how to do a variety of things with Rx (I put links to a few of them at the end of this post). And no, I am not going to write another tutorial or explanation on how streams and observables work. What I want to do is to provide a straightforward, clear and mostly theory-free summary of what you can do with RxSwift, and why you would want to use it. Since there is so much to cover with Rx, I’m going to break this down in a series of 3 blog posts. Let’s get started with the first part!

Part 1: Data Binding, control events and gesture recognizers

  1. Data Binding

“Data binding” sounds like another one of those fancy words thrown around to make things sound fancy, but it’s really quite simple. Let’s say you have an app that requires users to write their name in a text field. As they do, you want to greet them with a message that says “Hello, \(Name)”. Pretty basic, right? In a non-reactive app, you would add the UITextFieldDelegate protocol to your view controller and implement the textFieldDidEndEditing method to track when the user has finished writing their name, and at that point you would set the label’s text to say hello to that name.

Unfortunately, dealing with delegates can get quite annoying. What if you have more than one text field? You would have to add checks to make sure the user has finished editing the right text field. And what if your client decides the label should be updated as the user writes their name, and not just when they’re done editing the text field?

In reactive, that kind of behavior can be achieved through data binding. In short, you want to bind the data the user provides to you in the text field to another UI object (the label). With RxSwift, there is nothing simpler than binding data. In the case I just mentioned, this is what it would entail:

var nameField = UITextField()
var helloLabel = UILabel()
override func viewDidLoad() {
nameField.rx.text.map { "Hello \($0)" }
.bindTo(helloLabel.rx.text)
}

Let’s break this down: first, we take the text field’s text, and we map it to be in the format that we want to set in the label. In this case, it simply means adding a hello before the text (aka the user’s name), which, because map is a closure, can simply be referred to as an nameless closure argument ( $0 being the first argument, $1, the second and so on). We then bind that mapped text to the text in the label. And that’s it, job done! No delegates, no if statements, only a little bit of straightforward and concise code.

Now I know what you’re thinking: that’s great and all, but how many apps actually do something like this? All I can tell you is, don’t get stuck on the examples. Being able to bind data to views is very powerful, just think about it: you could have a view’s backgroundColor change depending on the weather, navigate a user through your store app based on their location, using some very simple logic, based on data that could potentially change. Again, I won’t get too much into the theory, but this is the main idea behind this.

2. Control Events and Gesture Recognizers

If you’re unfamiliar with events, they are basically anything that the user can do on your app: tap, swipe, drag, and so on. When the user presses on a button, your app detects that as a UIControlEvent of type .touchUpInside. If you’re using storyboards, you have probably seen that when creating your @IBActions. In that case, you probably haven’t thought much about your buttons actions. I’ve written quite a bit about why I never use storyboards, and if you’re like me, then this code should unfortunately look very familiar:

var button = UIButton()override func viewDidLoad() {
button.addTarget(#selector(ViewController.loginUser), target: self, event: .touchUpInside
}
func loginUser() {
// Implementation here
}

I’m going to say it straight up: I loathe selectors. They’re unclear, lead to dirty, scattered code and they increase the risk for errors. With Rx, this is how you would add an action to a button:

var button = UIButton()
var disposeBag = DisposeBag()
override func viewDidLoad() {
button.rx.tap.subscribe { onNext _ in
// Implementation here
}.addDisposableTo(disposeBag)
}

Don’t get too stuck on the disposeBag or the subscribe call here, just think of them as necessary steps to get your code to work (you’ll find more information about these in the resources I refer to at the end of this post).

What about when you need to execute some kind of logic when a view that does not have any control events (such as a UILabel or UIImage) is tapped? Unfortunately, the only way to do so with UIKit involves using another one of my least favorite UIKit features: gesture recognizers.

let label = UILabel()override func viewDidLoad() {
// Show example of gesture recognizers
let gestureRecognizer = UITapGestureRecognizer(target: self, action: “handleTap:”)
label.addGestureRecognizer(gestureRecognizer)
}
func handleTap() {
// Your logic here
}

Same goes for any sort of gesture you need to respond to, such as a swipe, drag, pan etc. If you want your view to respond to multiple gesture recognizers, you need to create and add every single one of them and their appropriate action methods. Not only does this involve quite a bit of boilerplate code, but it’s also incredibly messy and error prone.

And you’ve guessed it, Rx makes this ridiculously easy:

let label = UILabel()
let disposeBag = DisposeBag()
override func viewDidLoad() {
label.rx.gesture(.tap).subscribe {onNext (gesture) in
// Your logic here
}.addDisposableTo(disposeBag)
}

If you need to handle multiple gesture, this is all you have to do:

let label = UILabel()
let disposeBag = DisposeBag()
override func viewDidLoad() {
label.rx.gesture(.tap, .pan, .swipeUp).subscribe { onNext (gesture) in
switch gesture {
case .tap: // Do something
case .pan: // Do something
case .swipeUp: // Do something
default: break
}
}.addDisposableTo(disposeBag)
}

This is all provided by an RxSwift view gesture wrapper called RxGesture.

I am going to end here for today, but stay tuned for the next part of this series! Don’t hesitate to ask your questions in the comments and to let me know if there is something you would like me to cover, or something I could improve on!

Resources:

--

--