RealmResultsController

What is it?

In a single phrase, we can say that

RealmResultsController is a CoreData’s NSFetchedResultsController equivalent for Realm written in Swift

The Redbooth iOS App has a heavy use of CoreData and NSFetchedResultsController, so when we decided to start using Realm we faced our first problem, there was no equivalent for it. We looked at the existing libraries (like RBQFetchedResultsController) but at the moment it was written in Objc and we wanted something purely Swift 2.0 and with some extra features. At that point, we decided to write our own solution and make it open source!

If you are not familiarized with NSFetchedResultsController (Apple Docs), it allows you to efficiently manage the results returned from a Core Data fetch request to provide data for a UITableView object. NSFetchedResultsController monitors changes in DB objects and notify the view about those changes allowing you to be reactive about them.

We love Realm, is faster than CoreData, but we think it needed a feature like this to make it even better. RealmResultsController does the same for a Realm request with a couple of extra features.

GitHub_Logo

 

How it works

Realm Limitations

There are two important limitations to consider when building an add-on for Realm

  • There aren’t fine-grained notifications, we can’t know easily when an object has changed in a Realm, only when a write transaction finishes.
  • The Objects are not thread-safe so our library has to work around that

Solutions

We built a Realm proxy that implements the same functions (add, create, delete…) and ends calling the original ones, but in the middle allows us to detect all the operations done in realm objects during a transaction.

You must use these methods so the RRC can listen to all the changes in Realm.

 

The library does all the hard work in background, mantaining an updated cache and calculating the indexPaths for each operation. But since Realm Objects are not thread safe. Instead of sending Realm objects directly to the RRC, we mirror them using Reflection in swift, so we end up with an identical object that is NOT associated to any realm and therefore it is thread-safe to operate with.

The RRC does all operations in these thread-safe objects, and for the public API, we offer two solutions:

  • When initalizing the RRC, you can pass a mapper function (T -> U) from your Realm.Object (T) to another non-realm object (U). If you do so, the RRC delegate methods will return those mapped non-realm objects intead of the original ones.
  • If you don’t pass any mapper, the RRC will just return the mirrored objects (remember they are not actually inside any Realm, i.e. they are thread safe)

For more details about all the RRC methods, initializers, etc… please take a look to our Repository

For reference, this is a diagram of the RRC structure:

I want to use it in my App!!

Ok, let’s say we have a Realm database with a model called Task and a model called Project and we want to show these Tasks in a UITableView, but only the not resolved ones that belong to me.

Also, we want to sort them by Name and organize them in sections depending on which Project they belong to.

First step: initialize the RRC

First, we need a RealmRequest object, it represents what we want to fetch from DB.

With the RealmRequest we can initialize our RRC.
This is an RRC that fetches Task and maps them to TaskPOSO objects

There is a delegate protocol that you should conform to in order to receive all the RRC notifications:

Then, to start receiving updates, we just need to:

The Delegate methods are almost equal to the NSFetchResultsController ones and you will receive updates the same way you did with NSFetchResultsController:

A generic implementation could be:

At this point we have the RRC fully configured and ready to use, but we need it to integrate it with the UITableViewDataSource methods:

Now we are settled!!
If we create a new Task that meets the requirements, modify or delete a existing one, we will be notified.

For a more detailed working example, check out the RealmResultsController Repository

 

Conclusion

We’ve been really happy working with Realm, and now that we have an alternative to NSFetchResultsController even more. RealmResultsController aims to extend and improve Realm adding a feature that is very well known for CoreData users.

It also adds a couple of features (mapping and filtering) that weren’t in the original controller but we think that they can be really useful to make better and more explicit request to Realm. Also, adding a mapping feature allows us to separate the view from the model, we don’t receive models at the view level.

RealmResultsController can help you be more reactive in your views to model changes in your database without using pure reactive programming.

It is 100% covered with tests, thread-safe and a reliable library that we use in our own app. We’ll be happy to receive all the feedback you have about it, if you detect a bug or have a feature request, please fill an Issue in our Repository or just send a PR directly 🙂

GitHub_Logo

 

Isaac Roldán

In a flying trapeze inside a Tardis - iOS Developer at @redboothHQ

 

Leave a Reply

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