One of the absolutely amazing things about Reactive Programming is the ability to bind your User Interface to your Model. When the model updates: BOOM, the UI responds. If you ever want to test or inspect the logic of the bindings, it is all contained in the View Model so it’s far better than MVC or putting all binding logic in the View Controller itself.

The challenge is how to do it! This post will assume some knowledge of the workings of RxSwift and is specifically about binding rather than all the building blocks.

I’ve experimented with a few different ways of doing this but in this example I’ll show you one way where we declare what we need for binding upfront. This makes it easier to test.

In this example we’re going to handle the scenario when a user taps a button on the view, it’s going to send a message to the view model and it will change it’s data which will update the UI via bindings.

This story begins, as all great stories do, with a Protocol:


1
2
3
4
5
6
7
8
protocol ViewModelling {
// We'll use Associated Types here because we don't know the specifics of the View Model
associatedtype Input
associatedtype Output

// This method will be responsible for giving us the output we'll bind to later
func generateOutput() ->; Output
}

As you can see we’ve created a protocol which describes what’s about to happen: we’ll supply an input and the view model needs to provide us with an output to bind to our UI. Although a bit contrived in this instance, we’ll create structs for our input and output. If we only have on property to bind to a struct is probably overkill, but things can change quickly:


1
2
3
4
5
6
7
8
9
10
class ViewModel: ViewModelling {
// We can define a nice input type here
   struct Input {
      let buttonTap: Observable
   }
// We also know what to expect so we can bind to it in the View Controller or a Proxy Binder in between
   struct Output {
      let wasTappedTitle: Observable
   }
}

We’ve created a ViewModel class which will give the View Controller its properties to bind to. The question is: What are we passing to and fro? Hang in there, we’re getting to it.

Let’s create a property on the view model that represents our input and create our initialiser:


1
2
3
4
5
let input: Input

init(withInput input: Input) {
    self.input = input
}

Now we’re almost ready to start Binding! The thing about that though is that when things are listening for changes, there has to be some way of disposing of these bindings. Rx uses a thing called a dispose bag to get rid of subscriptions to observables. Let’s create one now in the View Model:


1
let disposeBag = DisposeBag()

The dispose bag will get rid of the subscription when it’s time to leave it behind… You’ll get used to it!

Let’s add that method from the protocol now:


1
2
3
4
5
6
    func generateOutput() -> Output {
       
        setupSubscribers()
       
        return Output(wasTappedTitle: titleText) // we're going to add this property in a second
    }

We’re going to subscribe to the button tap in a method we’ve described above and we’re returning a private property called titleText that is listening for that binding and will change accordingly. Let’s fill this in now:


1
private let titleText = BehaviorSubject(value: "Title not set yet")

So we’ve made a BehaviorSubject which basically is an observer and observable with an initial value. Basically this is a String that can change its’ value but it could be an array of Posts for a social media app or just about anything you can imagine.


1
2
3
4
5
6
7
8
9
    private func setupSubscribers() {
// get a reference to the input and make sure it's an observable
        input.buttonTap.asObservable()
// Subscribe to it
        .subscribe(onNext: { [weak self] _ in
// Update the property above
         self?.titleText.onNext("I was tapped!")
       }).disposed(by: disposeBag)
    }

In the Rx world we can observe ‘streams of data’. What on earth does this mean? Well, rather than

1
let name = "Laurie"

,

1
name

is something that can change at any time, or be nothing at all. Think of it like your phone is an observable thing and it gives off different things we can subscribe to – your social media notifications for example: we always want to be up-to-date with what’s happening, right?

In the iOS world though we need a way to bind to actual Cocoa Touch components: good old buttons and table views etc. Thankfully we can simply import RxCocoa which has this all taken care of already.

We’re going to head over to our View Controller and import RxCocoa:


1
2
3
import Foundation
import RxSwift
import RxCocoa

Add a label and create an outlet and create a view model property:


1
2
3
@IBOutlet weak private var titleLabel: UILabel!

var viewModel: ViewModel!

In the ViewDidLoad method let’s get things binding!


1
2
3
4
5
6
7
// Create an input by passing in the rx.tap value from the button, but it needs to be cast as an observable
let input = ViewModel.Input(buttonTap: connectButton.rx.tap.asObservable())
// Init the view model        
viewModel = ViewModell(withInput: input)
// Call the method we made and bind the Output to our UI text element
// Don't forget to dispose of subscriptions        
viewModel.generateOutput().wasTappedTitle.bind(to: titleLabel.rx.text).disposed(by: disposeBag)

Build and run and you’ll get things binding just fine:

Rx swift bind view model

 

This is a super-simple example but it shows you the basics of binding things together.