UI database bindings with Realm & ReactiveKit

UITableView is truly a heart of iOS user interface. It does not matter whether you are changing settings, going through unread emails or sending messages. Provided that you have used your iOS device recently, it is almost certain that you have stumbled upon a table view.

Rendering a table with arbitrary data is a really simple task. You just conform a class to UITableViewDataSource protocol by implementing two required functions. So far, so easy. The next step is to make this table represent some actual data from your app. This is where things are getting complicated. Some typical requirements are:

The data is stored in a local database, filtered and sorted according to a query.

Results of the query can be updated at any time, even by a table itself (marking TODO notes as completed, deleting favorite recipes and so on).

The data is synchronized with a backend service, either on demand or automatically (in the background).

What is more, the points above are not mutually exclusive. In fact, it is typical to have all of them at once in a single view controller. How do you handle UI updates for that? Wiring a synchronizer and a view controller to the notification center seems to do a trick. However, calculating table updates based on a queryset changes is not a trivia. Yes, it is possible to reloadData() everytime, but this won't cut it for marking a single object deleted.

Is there any other option? Yes, it is called NSFetchedResultsController and comes shipped with CoreData. It reports any changes made to a queryset so that you can map them directly to table view updates. Is it convenient to use? Well, just a quick look at the CoreData docs and I am already intimidated by a number of delegate methods that I need to implement. How about you?

You may wonder whether this article is to complain about how much code dedicated to UI updates is needed for every table view. No, it is not. In fact, I am going to show the opposite.

You do not need any dedicated code to handle UI updates for a table view.

What kind of magic is that?

Sample TODO app

Please, bear in mind that this article is up to date as of Xcode 7.3, Swift 2.2 and ReactiveKit v2. It is going to be updated for Swift 3 after it is out of beta.

To illustrate the idea, I have created a sample TODO note application. You can clone its source code from Github. The screencast from the app is presented below.

3rd party libraries

The first step for updateless table views is to attach necessary dependencies to a project. To accomplish the result we will need:

Realm Swift - a Swift version of a great object database for mobile devices,

ReactiveKit - a library that supports reactive programming along with ReactiveUIKit which provides bindings for UIKit controls.

Why Realm? There is at least a couple of different reasons to use Realm. For the project it is the best choice because it can notify about queryset updates similar to CoreData, but the API is much more concise.

Why ReactiveKit and not any other reactive programming library? There is no particular reason other than my familiarity with a framework. You can achieve the same result using RxSwift, ReactiveCocoa or any other (F)RP library that you feel comfortable with.

Carthage

Despite using only CocoaPods for dependency management in the past, I decided to change my approach. This decision was based on two factors:

I wanted to give Carthage a try for a long time,

the painful experience of using CocoaPods on my previous Swift project.

The problem with CocoaPods is that it rebuilds the whole workspace every time a target is changed or DerivedData/ directory is emptied. Having over 15 dependencies attached and being a victim of frequent Xcode syntax highlighting problems and crashes I spent a considerable amount of time observing a build progress bar. Since it was not entertaining, I have switched to Carthage for the time being.

Installing project dependencies requires a couple of steps. Firstly, you need to create a Cartfile:

Secondly, you need to run carthage update command. It is noticeably slower than pod install counterpart, but it results in much shorter average build time.

After a build process is completed, frameworks need to be attached to a project. Carthage readme documents that really well, so it is a matter of following steps mentioned there.

Reactive programming

ReactiveKit is a library that supports Functional Reactive Programming (FRP). If you are familiar with the term you can skip this section. Otherwise, do not worry. It is there to describe a pretty simple concept of building a software.

Reactive Programming (RP) focuses on a data flow. The idea is that there is an input data that changes constantly and the code should specify how to transform it to an output. Let's assume that there are 5 people reading my blog right now, two of them being female. Or, expressed in a programming manner:

male = 3
female = 2
total = male + female // 5

Now, a next female hits the page. It changes the input data:

female = 3

In an imperative programming world, a total value would not change. It was calculated once and it will stay this way until it is explicitly changed. In that case total == 5 still evaluates to true, but it certainly is not valid, since I already have six visitors!

If I wanted to show a total number of visitors, reactive paradigm would be a much better fit. The total value (output) would be updated every time that either male or female values (input) are changed.

The only difference is that array of notes is additionally wrapped inside a CollectionProperty. Thanks to CollectionProperty, every time an array is changed, a subscriber gets notified about it. A simple example can be found in ReactiveKit readme.

Upon running an application you should see a list of two entries. You might have noticed that the code is a little bit shorter than the delegate counterpart. But the biggest advantage of that approach is yet to be discovered. Now, add a new button to the view controller. It can invoke any of the three action types below:

insertion (example: notes.append(TODONote(note: "Third"))) ,

deletion (example: notes.removeLast()),

modification (notes[0].note = "Not a first note anymore").

Test run the application. Yes, that is right. The changes made to a notes array are automatically reflected in a table view now.

Using ReactiveKit with Realm

We are halfway there. Our table view is refreshed automatically, but we still have to wire up a database query to a CollectionProperty. It is high time to switch to an actual implementation of TODONote model:

It is a lazy loading collection. Objects are fetched from a database only when they are needed.

It is updated automatically to reflect a query state.

It conforms to a RealmCollectionType, which derives from CollectionType.

The last point is especially useful for us. Since ReactiveKit's CollectionProperty wraps around CollectionType we can instantiate that with Realm's Results directly:

let notes = CollectionProperty(realm.objects(TODONote.self))

The bad news is that binding such a property directly to a table view would result in a crash or no updates at all. It is because ReactiveKit provides standard protocol extensions for Array type, which triggers an update event upon invoking any method that can modify this array. Such overloads for Results are non-existing in standard ReactiveKit library, since it does not come bundled with Realm.

The good news is that Realm supports collection notifications which is exactly what we need to implement a CollectionProperty. Even better news is that Realm's notifications use almost the same data format to denote collection changes as ReactiveKit does. Having that knowledge, we can easily implement a bridge between the two:

From now on every change in a database that modifies notCompletedNotes query will automatically trigger UI updates. There are numerous advantages of that approach:

There is no need to worry about manually exchanging notifications anymore. It does not matter which action/object triggered the change. Whether it is a button inside the same view controller or a synchronizer class managed in the AppDelegate, all the data changes are handled in exactly the same fashion.

There is no need to worry about managing threads. ReactiveKit's data bindings are always updating UI on the main thread, so it does not matter whether the database was modified in a background or not.

Single source of truth - the database. There is no need to duplicate data structures and so there is no risk to have any discrepancies between them.

I strongly advise you to try this approach yourself. I was really surprised about how easy and reliable that was.

Please note, that the code presented in snippets is for presentation purposes only and contains shortcuts, like creating notes in init(), that you should never ever use in a production code.