Functional Reactive Programming in Swift 3

Data Binding with RxSwift

This post is a tutorial that will teach you how to bind data to views using RxSwift, which is a part of the Functional Reactive Programming (FRP) design pattern — where views react to changes to data. FRP is not MVC. These design patterns are distinct from each other. Unless you have a good reason to use both in a single project, I suggest that you be consistent in your architectural pattern — stick to just one!

As a reminder, Model View Controller (MVC), consists of having a View Controller be a “middleman” between a Data Model and the View on screen.

The Model and View never directly communicate, but use the Controller to pass information.

Note that when using the MVC design pattern, the Model and the View never directly communicate.

An alternative to MVC is a design pattern called Functional Reactive Programming (FRP). FRP is quite the opposite of MVC — in regards to the fact that the Model and the View have a direct connection.

In this tutorial, we’ll only be looking at binding data to views using RxSwift— your views will update automatically whenever the data is updated.

This tutorial requires you to use a Cocoapod called RxSwift. The link I provided is for Swift 3. Please use this branch of RxSwift if you are using Swift 2.3.

What we’ll be doing is setting up a direct connection between the data and the view. You can fork and clone my starter repo here.

Let’s use the example of having a UILabel that is updated upon text input from a UIAlertController .

Normally, you might have a variable that looks like this to represent the name value:

let name: String = "Julia"

To convert this variable into one that will be compatible with RxSwift, we have to change the type of the variable.

let name: Variable<String> = Variable("Julia")

Note that our variable is now of the Variable class, which is part of the RxSwift library.

As you might have noticed, the Variable class serves as a wrapper for the data stored in the variable. So, you can still access the string “Julia” by calling name.value .

Next, we call the asObservable function on our variable, name . We then call the bindTo function on the result, passing in the view element that we are binding to.

name.asObservable()

.bindTo(nameLabel.rx.text)

In this particular case, we are binding to the text property of a UILabel named nameLabel . However, the bindTo function also allows us to bind to other properties of views, such as backgroundColor .

And lastly, we have to initialize and use a dispose bag. The binds that we create between data and views will persist even after the View Controller is deallocated. The dispose bag will make sure that the bindings are also deallocated when the View Controller is deallocated.

let disposeBag = DisposeBag()

In order to add the binding to the dispose bag, we have to call one last function on the binding. Here is what the final binding should look like:

name.asObservable()

.bindTo(nameLabel.rx.text)

.addDisposableTo(disposeBag)

Lastly, in order for your views to change, you need to change the data! The variable in this tutorial changes based on text input from a UIAlertController , we’ll implement the code that changes the view.

Normally, your action closure might look like this:

let okAction = UIAlertAction(title: "OK", style: .default) { action in

if let textInput = alert.textFields?.first?.text {

self.name = textInput

self.nameLabel.text = self.name

}

}

Note that you have to update your views as well as your data. When we bind our views to the data, we don’t have to update the views. The binding implies it automatically updates! All we have to do is change the data itself.

let okAction = UIAlertAction(title: "OK", style: .default) { action in

if let textInput = alert.textFields?.first?.text {

self.name.value = textInput

}

}

Remember that the type of name is Variable —meaning the data is enclosed in a wrapper. Instead of updating the name variable itself, we have to update the data, which happens to be at its value property.

Here is a link to a Github repo with the working code from this tutorial. Please feel free to reach out if you have any questions!