Why we dropped Realm

Before we begin, I should describe why we started using Realm in the first place.

Realm is fast. Really fast. At least in this comparison to SQLite + SharkORM. In most use cases, I rarely perform 10.000 select statements, and in most apps I have been a part of developing, the network speed has always been the determining factor. Your mileage may vary, though.

Realm is incredibly easy to set up. All you need to do is have your model objects inherit from the Realm base object. No tables need to be defined. Even migrations are as simple as incrementing a schema version integer on the global Realm object.

Realm is even thread safe (sort of). As long as you don’t move your model objects between threads.

∙   ∙   ∙

This is where things start going downhill.

Since it isn’t possible to move model objects between threads, then they have to be re-instantiated on a background thread if you want to do larger, heavier updates.

This shouldn’t be a big deal. Instantiating an object isn’t a difficult or slow operation. Here are the steps I would expect to be involved in updating an object:

object.property = value
// switch to background thread
object.save()

That would have been neat, now wouldn’t it?

In stead, here is what is needed:

class MyObject {
    var id
    override static primaryKey() -> String {
        return "id"
    }
}
let id = object.id
// switch to background thread
let copyOfObject =
    realm.objects(MyObject).filter(id).toArray(ofType: MyObject)
realm.write {
    copyOfObject.property = value
}

And what if you want to change the value of your primary key of your object, say if you created a temporary object and now want to assign an id to it? Sorry that cannot be done.

Also, whenever you access an object, remember to always call…

object.isInvalidated

… and if it happens to be invalid, then you cannot do anything with it. Not even get its primary key so you can reload it.

In the end

Every single Realm operation has to be wrapped in a try/catch block because every single operation may throw an exception.

Every single object access has to be prefixed with isInvalidated().

The end result is that while other persistence frameworks have significantly more setup, that setup is to a large degree a one time operation. Once the setup code is written you can pretty much just leave it alone. In Realm, the quirks of the framework infects every single operation which in any way reads or writes a realm model object.

Realm does not encapsulate and isolate your persistence decision process, it spreads that process all over your code.

∙   ∙   ∙

Given that, I’d rather just write plain old SQL myself.