phipsG phipsG - 1 month ago 18
Swift Question

Uncaught RLMException when accessing Realm from Singleton

This is not a duplicate question, please just continue reading!

I'm getting the "'RLMException', reason: 'Realm accessed from incorrect thread'" error message displayed when I use my

RealmBackend
singleton in a DispatchQueue.

This is my class:

class RealmBackend {

static let shared = RealmBackend()
var realm = try? Realm()
}


There are functions in it like
addObject()
which are accessing the
realm.commitWrite()
and the
realm.beginWrite()
functions.

Now I call the
addObject
function from a callback (
UIRefreshControl
) with the
DispatchQueue.main.sync
since I'm assuming the Realm object was created on the
main
Thread (I read somewhere on Github that you need the same Threads for instantiating and accessing the
Realm()
value).

As I stated before I always get this
RLMException
, has someone faced the same problem?

TiM TiM
Answer

Realm instances are thread confined, meaning that they will only work on the thread in which they were created. If you try and pass an instance between threads, you'll get that incorrect thread exception you saw. This is done by design to guarantee Realm's ACID compliance.

There's not really much point in holding onto a hard reference to Realm instances, especially in singleton objects. Once a Realm instance for a specific thread is created, Realm will internally hold onto that reference and will simply re-supply it if you try and create a new one with the same settings down the line. As a result, there's very little overhead in calling Realm() multiple times.

If you need to use a Realm instance with a different configuration than the default Realm, Configuration objects are thread safe, so you can simply store a single reference to that, and pass it to Realm() whenever you need it.

class RealmBackend {

    static let shared = RealmBackend()

    // A Configuration for a Realm in the caches directory
    let cacheConfiguration = Realm.Configuration(
                     fileURL: URL(fileURLWithPath: /* Path to the Realm in Caches */),
                     readOnly: true)

    func addObject() {
        let cacheRealm = try! Realm(configuration: cacheConfiguration)
        // ... add object to cacheRealm
    }

    func getObject() -> Object {
        let cacheRealm = try! Realm(configuration: cacheConfiguration)
        let object = realm.objects(Object.self).first
        return object
    }
}

In this case, since Realm is being created on demand, even if the singleton methods are being called on separate threads, Realm will internally be able to provide the correct instance.