Swift Bindings and Reactive Data Sources using Bond

Swift Bindings and Reactive Data Sources

Mobile app consumers have raised the bar for their expectations while scrolling through an app. Nowadays, everyone wants to see smooth transitions, pixel-perfect apps, and fewer steps. Even a small visual distraction can make the user delete your app. In other words, your app has to be perfect.

How do you handle your data changes?

There is also another important thing, and that is how you handle the data changes to the UI. I have met tons of apps with poor handling of data changes. For example, you are pulling to refresh the table view content and suddenly the whole content disappears and reappears after 2–3 seconds. In most cases, you are getting the same results back as before the “pull to refresh”, so nothing has really changed. Sounds familiar?

Let’s avoid this kind of situations, and handle data changes properly by using bindings and reactive data sources.

Reactive Programming

For those who aren’t familiar with the term, reactive programming is an asynchronous programming paradigm concerned with data streams and the propagation of change. For example, all changes to the model will be automatically reflected in the associated view.
If you are interested to find out more about reactive programming click here.



Swift Bindings with Bond

Bond is a Swift binding framework that takes binding concepts to a whole new level. It’s simple, powerful, type-safe and multi-paradigm – just like Swift. It simplifies state changes by using bindings and reactive data sources.

This library is in my all-time favorites. You can attach it to any component that you like. I will show you how to use Bond with few examples, so you can get the idea of how it’s working.

Installation

For the installation, I am using CocoaPods. I highly suggest that you do the same. Just add the below code in your Podfile and run pod install.

target 'YOUR_TARGET' do
use_frameworks!
pod 'Bond', '~> 6.4.3'
end

I’m using the latest version of the framework from the day I wrote this post. For version changes, please check here.

Add import Bond to the top of your class so you can use all the Bond methods.

Events

I will start by showing you how to get rid of the annoying process of IBAction and use the simplified approach from Bond instead.

_ = yourButton.reactive.tap.observeNext { print("Button tapped.") }

This will observe your button tap. It listens to touchUpInside because it’s the most frequently used event. If you want to handle other events you can use:

yourButton.reactive.controlEvents(.touchUpInside).observeNext { e in
    print("Button tapped.")
}

Another example would be observing the text changes in a UITextField. Knowing that there is no native approach to this situation, Bond provides us with a simple solution.

_ = yourTextField.reactive.text.observeNext { text in
    print(text!)
}

Now, let me show you a simple binding of the typed text into a UILabel. The text will get transformed by using the .map closure and propagated to the label. $0 is the typed string, so you can add any string transformation that you need.

yourTextField.reactive.text.map{ $0?.capitalized }.bind(to: yourLabel)

Or, you can use the above example but provide a condition instead. Let’s say you need to change the button enabled state as someone types in the text field.

txtField.reactive.text.map { $0!.characters.count != 0 }.bind(to: yourButton.reactive.isEnabled)

Observable

Observables are signals and a typealias for the ReactiveKit Property type. Whenever the state of the Observable changes, an observer will be notified.

let animal = Observable("Dog")
animal.observeNext { value in
  print("Hi \(value)!")
}

If you can see from the example, whenever the animal observable changes its value an observer will be triggered. To change the value just call animal.value="Cat". To bind an Observable with a UI component just use animal.bind(to: yourLabel).

Bond also supports two-way binding by using bidirectionalBind. It means that if the view value changes, it will update the Observable value and vice versa.

animal.bidirectionalBind(to: animalTextField.reactive.text)



Reactive Data Sources

By using reactive data sources, it allows us to easily observe changes in a table or collection view. That means whenever the array changes, the data source methods will update automatically. No need of adding reloadData() on each array change, and it will update only the changes that were made.

We need to use MutableObservableArray or ObservableArray that will observe for changes and pass the changes automatically to the data source methods.

let array = MutableObservableArray([“John”,”Michael”,”Steven”])

I will now present you how easy and short it is to implement the data source of a table view. You don’t need to connect the UITableViewDataSource with the table view, as Bond handles that for us.

The mandatory numberOfRowsInSection()and cellForRowAtIndexPath() , are “packed” under the array bind() method. In the closure, you can add your own cell logic. See the example below.

array.bind(to: tableView, animated: true) { dataSource, indexPath, tableView in
   let cell = UITableViewCell(style: .subtitle, reuseIdentifier: “cell”)
   cell.textLabel?.text = dataSource[indexPath.row]
   return cell
}

Now, let’s say that the array needs to be updated. At this point, we need to only focus on the array, and forget about the table view and whether it’s going to update or not.

Here are some methods that you can use to make changes to the array.

array.append("Brad") /* appends array with a new object */
array.insert("Brad", at: 2) /* inserts new object at the given index */
array.replace(with: [“John”,"Brad",”Michael”,”Steven”], performDiff: true) /* replaces the array but updates only rows that weren't present in the previous array (in our case index 1) */
array.moveItem(from: 1, to: 2) /* items in array will change places */
array.remove(at: 2) /* removes an item from the array */
array[1] = "David" /* replaces the value at the given index */

By using these methods properly, we provide the best user experience possible. The data will be updated, and the user won’t get distracted in any way.

RECOMMENDED STORY: Introducing Clean Swift Architecture (VIP)

I have presented just a few of the many features that Bond offers. Binding and the reactive paradigm can bring your app to the next level, so I would strongly suggest using this approach. If you want to spread the message, please don’t forget to share this story.

Thank you for your attention!

Leave a Reply

Your email address will not be published. Required fields are marked *