Why We Went With Realm

For years, Core Data has been the go-to persistence library for Mac and iOS apps. Recently, an alternative called Realm has come on to the scene, and is becoming quite popular. We gave it a shot, and ultimately chose to use Realm over Core Data in AmebaOwnd.

This post was written with Realm Objective-C 0.92.3. There is also a Swift version, but it is only for iOS 8+.

I first heard about Realm in an IRC channel about iOS development. Having primarily used Core Data before, I was kind of surprised to see people who I know are very good programmers telling newbies not to use it. After comparing the two, I think I understand why.

Problems With Core Data

Let me just start by saying that I don’t dislike Core Data. I’ve used it in a number (almost all?) of my previous projects, both personal and professional. However, it’s not perfect.

Setup and Learning Curve

There is a lot of boilerplate involved in getting Core Data set up. Just to get your stack setup, you need to set up your “Managed Object Models”, at least one NSPersistentStore, NSPersistentStoreCoordinator, and finally one or more NSManagedObjectContext instances. Phew, let’s hope you didn’t screw it up!

Let’s face it, Core Data is certainly not the easiest library to pick up.

Managed Object Contexts

Each NSManagedObject you want to create must be inserted into an NSManagedObjectContext. You can’t have transient or temporary objects unless you create a temporary NSManagedObjectContext for them, or delete the objects when you are done with them.

Core Data is an object graph and persistence framework – not a database. This means that you cannot just “save one object,” because saving the context will save all object changes.

I often found myself with multiple contexts, mainly because Core Data objects are not thread safe.

My normal stack had one for background persisting to disk, one context for the main thread, and one context in the background for API updates and such. Then temporary contexts for screens that have ephemeral data, or isn’t necessarily saved right away.

Having to manage all these contexts can be cumbersome. It can be an exercise in architecture to structure your app to not be tightly coupled to Core Data.

Having to deal with NSManagedObjectContext isn’t a problem, but it can definitely feel troublesome sometimes.

Lack of Support

To be completely frank, it doesn’t really seem like Apple cares too much about Core Data anymore.

For example, there is at least one bug from 2011 that still isn’t fixed! This bug will cause your app to crash! Just by trying to use an auto-generated class in a way that appears completely normal.

I have also heard rumors that the source code of Core Data is messy, and that nobody at Apple really wants to go in and touch it. This is just a rumor I heard, so maybe don’t take my word for it…

Realm Makes it Easier

After getting a good understanding of Core Data, what it is, how it works, and maybe more importantly, how it doesn’t work, it’s a pretty decent library to work with. But wouldn’t it be nice if we had something we could just sit down and start using? Realm is like that. It’s also super fast, and I have noticed no performance decreases due to it.

Getting Up and Running

The Realm team has made this really easy on developers. There is no “object model” to define. To make an object I want to persist, all I need to do is make it a subclass of RLMObject:

class User: RLMObject {
    // It's important that you make your vars `dynamic`
    dynamic var id = ""
    dynamic var name = ""
    ...
}

To get access to the database, we can do it in one line of code:

let realm = RLMRealm.defaultRealm()

Creating, reading, updating, and deleting objects is also really simple. Really all there is to remember is that operations that need to write to disk (all but reading) must be done in a transaction.

// Create a non-persisted user object
let user = User(id: "329", name: "Caesar")
let invalidUser = // fetched elsewhere -- some user we want to delete

// Fetch a user
let predicate = NSPredicate("id = %@", "4889")
if let results = User.objectsInRealm(realm, withPredicate: predicate),
    let fetchedUser = results.firstObject() as? User {
    
    realm.transactionWithBlock {
        // Persist the newly saved user
        realm.addObject(user)
        // Update the fetched user's name
        fetchedUser.name = "Steve"
        // Delete a user
        realm.deleteObject(invalidUser)
    }
        
}

That is literally all it takes to get up and started using Realm. The only things that are a little tricky are that objects that have already been persisted are immutable – They will crash your app if you change their properties outside of a transaction.

Instead of littering our codebase with transactions everywhere, we created a generic data layer class that handles it all internally. Instead of returning the actual persisted objects, we made it return mutable copies, so then we can use them just like normal objects and persist the changes when we choose to.

Realm “Contexts” and Multiple Threads

Since Realm is a database, and not an object graph and persistence framework, there isn’t as much emphasis on making sure each object created is “in the realm.”

You can create your RLMObjects just like any other object, eg. let user = User(). It can be used like any other object, until it is persisted – then it is immutable. Unless you just make a mutable copy :)

Like Core Data, RLMRealm and RLMObject instances are not thread safe. You will need to get new instances for each thread you are working on.

The good news is that in Realm, transactions are synchronous. Changes are automaticaly merged between threads.

RLMRealm.defaultRealm() will return an instance of the default Realm for the thread it is called on. If you use it, you won’t have to worry about managing which instance you are dealing with.

Or you don’t have to use the default Realm, there are a number of constructors to choose from.

I think the main thing to remember is that you can’t use the same Realm instance between threads. Even so, the Realm API makes it so easy, you almost don’t even have to think about it.

Tons of Support

While the core C++ code is not available to us just yet, the Objective-C, Swift, and Java are available on Github. They are all released under the Apache 2.0 License.

Any issues or questions you have can asked right on Github. You can even contribute if you want!

The Realm team has really gone above and beyond when it comes to helping the Open Source iOS Community. Apart from the database, have open sourced jazzy and SwiftLint.

Bonus: Data Browser!

Realm comes bundled with a browser you can use to look at, and edit your data.

Realm Browser

How awesome is that?!

Never Looking Back?

I have used Core Data many times in the past. I’m pretty comfortable with it. Like they old saying goes, “if it ain’t broke, don’t fix it,” right?

That being said, using Realm feels like a huge upgrade. Maybe Core Data ain’t broke, but there are definitely times I felt like I had to fight it to get it to do what I want. Realm works just how I want it to from the start.

I won’t say that I’ll never, ever use Core Data again. But I will say that from now on, Realm is now my go-to persistence library. So go on and check it out!