The Realm API is Optimized for Performance & Low Memory Use

Realm Database series header

This is the second post in a multi-part series on the Realm Database; it highlights some of the foundation classes that make using the database a breeze in any of the star programming languages we support. If you missed the first post we recommend taking few minutes to read through. Also make sure to check out the third post on sharing code across platforms, the fourth post highlighting how a flexible, solid SDK like Realm’s empowers good development practices., the fifth post on Realm SDK features that allow developers to provide partial UI updates based on fine-grained notifications, and the final and sixth post, which shows how the features in the previous parts come together to make a database for modern mobile apps.


Since the Realm Database was specifically designed to be used on mobile devices, it’s built from the ground up to be efficient.

We’ve already discussed few aspects in the previous post about why the Realm Database performs so well:

  • it doesn’t use a third party storage engine,
  • it doesn’t use intermediate query language like SQL,
  • and it doesn’t need to continuously convert data back and forth as it reads or writes to the disk.

As we mentioned earlier, there are two somewhat different parts to the Realm Database: the C++ core and the SDKs that you use, written in the language you’re using to build your app.

So what does the Realm Database do in its SDKs to help you have more performant and robust code? In this article, we are going to have a look at some common patterns that do so.

Who Needs a Fetched Results Controller?

A common pattern in mobile development is displaying long lists of items, be it the user’s contacts, entries in a calendar, or list of tweets.

When using a “traditional” storage, you would often just copy items from disk into an array in memory, effectively duplicating your model — and if you’re not careful with copying arrays, you might just triple it as well.

Get more development news like this

If you’re dealing with very long lists, you’d like to be more lean than just loading all data into memory. You need to write code to load pages (or batches) of records from disk (preferably in the background to keep UI scrolling smooth) and copy only the current batch into memory. Then you have to keep track of how far the user has scrolled the list and load more batches as they scroll further.

A common solution to this issue would be using NSFetchedResultsController (on Apple platforms) or similar. But remember: this is a pre-fetching class that runs on top of an ORM that runs on top of an SQLite database. And that feels like a lot of middlemen right there between you and your data:

An app which uses a results controller, which uses an ORM, which uses SQLite

In contrast, with the Realm Database you use a class called Results, which helps you directly query objects on disk and load only the ones you actually are using at a given moment into memory.

Let’s look at some of the benefits.

First and foremost, defining an object query does not load any objects from disk. For example:

realm.objects(Repository.self)
  .filter("name contains[c] %@", searchTerm ?? "")
  .sorted(byProperty: "stars", ascending: false)

This code defines a kind of viewport to the database — you’re interested in Repository objects that have a name containing a given search term, and you’re interested in them in the order of their amount of stars.

You don’t need to execute or run in another way that object query. Realm will start loading data from the disk as you actually start iterating over the objects in that result set.

Results allows you to only load the data you actually need and use. (Within reason of course - you can’t realistically read isolated bytes from disk)

So when you chose to drive a UI table view with the Results class, you read from disk only the data to display the currently visible table rows.

The best part? You don’t need to do anything extra to achieve that. While your user scrolls through a table view with hundreds of thousands of rows, Results keeps in memory only the data needed to display the 5-6 rows you have on screen at a time.

Dealing with Lists? We Got This.

Let’s look at another class from the Realm Database’s API - List. The List class allows you to have a one-to-many relation between objects. For example:

class User: Object {
  dynamic var name: String = ""
}

class Repository: Object {
  dynamic var repository: String = ""
  let contributors = List<User>()
}

You are probably familiar with this kind of relationship from SQL databases. In your SQL database, you need to define an extra table that sits between the two tables - say users and repositories. Anytime you want to get the contributors for a given repository - you need to search through all relationships between all repositories and all users in your database to find the ones that you’re interested in.

Soon enough you end up with something like this (and you’ve seen this kind of tangled relationships if you’ve worked on complex SQL databases):

Tangled relational database tables

So if the repository EasyAnimation has two contributors, to get the details of these two users you need to search through all links between the records in users and repositories. Depending on how many repositories and users you have, the relationship index might be hundreds, thousands, or millions of records. And you have to work through those to find out the two records you’re actually interested in, every time you want to fetch them.

As you can imagine, this isn’t very performant. That’s why in teams working on very large databases you need to get permission from the team lead to use a JOIN clause in a database query (speaking from experience here).

In contrast, the Realm Database does not join tables and does not use SQL queries. A Realm Database is pretty much just objects, like you have them in memory. When one object points to another, the parent doesn’t typically copy the child’s data, right? Of course not, it just keeps a pointer to it.

That’s why getting the two contributors to a Repository object with the Realm Database means just keeping two direct pointers to two other objects, which you can use anytime you want. No lookups, no relationships, no indexes.

Realm relationships

List is really good at keeping one-to-many relationships. It works largely like an Array: it preserves the order in which objects were added to it, and it gives you methods to append, remove, or move objects to a certain index. And again, it costs almost nothing to create a List: that object itself only stores a list of direct indexes to other objects, and as you probably know indexes are cheap to store.

That being said, using List in creative ways can add a lot of performance to your app.

Let’s consider the following case: You have a Repository object that keeps a list of contributors, and some of those contributors are awaiting approval and access.

You want to display two lists in your app’s UI: one of the pending contributors and the other with the approved ones. You might be tempted to approach this in the way you’re used to working with other databases and write:

// this is the slow old way
class User: Object {
  dynamic var name: String = ""
  dynamic var isPending: Bool = true
  dynamic var dateAdded: NSDate = NSDate()
}

class Repository: Object {
  dynamic var repository: String = ""
  let contributors = List<User>()
}

//display pending users
realm.objects(Repository.self).first!
  .contributors
  .filter("isPending = true")
  .sort(byProperty: "dateAdded", ascending: false)
  
//display approved users
realm.objects(Repository.self).first!
  .contributors
  .filter("isPending = false")
  .sort(byProperty: "dateAdded", ascending: false)

Again - there’s no need to go this way with the Realm Database.

This would be a valid approach if you were using an SQL database. It would be the most you could do because you would need to filter the same tables over and over again. However, think about this one more time: Why do you need to filter and sort those object every single time you want to show them on screen?

List to the rescue! How about keeping two separate lists: one of the pending contributors and another with the approved ones? How would that help you ask?

You will never have to filter or sort the users again (and frankly these two operations are what is slowing down your queries).

In a list, you will essentially iterate over the precise objects you need in the precise order you want! In a sense, you pre-filter and pre-sort the objects in each of the two lists, thus doing the work only once. Then you simply iterate over the collection when you need to display the data.

Let’s have a look at that more performant setup. If the dateAdded property was used only for sorting it be removed safely. isPending can stay but it won’t be used for filtering - only to determine the status of a single User object when needed.

// the easy Realm way
class User: Object {
  dynamic var name: String = ""
  dynamic var isPending: Bool = true
}

class Repository: Object {
  dynamic var repository: String = ""
  let approvedContributors = List<User>()
  let pendingContributors = List<User>()
}

And of course you don’t need to query the contributors anymore, you can just iterate over the two lists. When you add a new User object, add it to pendingContributors; when the user is approved, remove the User from pendingContributors and add it to approvedContributors.

// user requesting repo access
let user = realm.object(ofType: User.self, forPrimaryKey: id)
try! realm.write {
    repo.pendingContributors.append(user)
}

//later, when the user is approved
try! realm.write {
  user.isPending = false
  if let index = pendingContributors.index(of: user) {
    pendingContributors.remove(objectAtIndex: index)
  }
  approvedContributors.append(user)
}

You can have further lists added to the same Repository object, since they’re not expensive to create or maintain.

Finally, since lists only keep direct links to existing objects, you can have the same object added to multiple lists. You will not take any performance hit for doing so.

For example the same User object might be both in the list of approved users and in the history list of commits to the repository object. Each of these lists can drive a different screen of your app:

Lists powering view controllers

Now that you have a better understanding of Realm’s lists - compare one last time what it requires to show a repository’s commits on screen with SQL tables compared to object lists.

Using the former, each time the user opens the commit list screen you will need to go over the table of all commits, filter all records to only the current repository and match the users table against the results, and finally sort all those records.

When using a List, you will just read the first few objects from the Repository’s commits list and display them on screen. Whoa! 👌

The List class is designed to power item lists, and those are everywhere in mobile UI. You can get the most out of this class if you step away from how you’re used to using other storages and think about your data in terms of objects and object graphs.

Last but not least - we’ve been using the Swift Realm SDK in this article, but things work exactly the same way on other platforms as well. Building efficient object queries and object lists are implemented in the Realm Database Core, so they work the same way across platforms and programming languages.

In the next posts in this series, we’ll have a look at more classes provided by the Realm Database SDK and how they aid quick and efficient mobile development.

We Hope You Like What You’re Seeing!

We’ve just scraped the surface of the many ways the Realm Database has been designed to solve present day apps’ challenges.

In fact, if you have few extra minutes, you can read more about the Realm Database:

In the next installment of this series, we’ll take a look at the ways the Realm Database’s API empowers clean software architecture and modern best practices.

We’re going to leverage that modular code and explore a multi-platform project, which shares code between tvOS, iOS, macOS, and watchOS in the same project!

See you next time! 👋

Next Up: What makes Realm different #3: Realm Offers a Multi-Platform Database

General link arrow white

About the content

This content has been published here with the express permission of the author.


Marin Todorov

Marin Todorov is an independent iOS consultant and publisher. He’s co-author on the book “RxSwift: Reactive programming with Swift” the author of “iOS Animations by Tutorials”. He’s part of Realm and raywenderlich.com. Besides crafting code, Marin also enjoys blogging, writing books, teaching, and speaking. He sometimes open sources his code. He walked the way to Santiago.

4 design patterns for a RESTless mobile integration »

close