kodeusz
kodeusz

Reputation: 188

Realm Swift iOS - Terminating app due to uncaught exception 'RLMException', reason: 'Realm accessed from incorrect thread'

I have a problem with loading objects from Realm Database in Swift 2.0.

I call:

    var cities = try! Realm().objects(City)

and my app crashes and I give "Terminating app due to uncaught exception 'RLMException', reason: 'Realm accessed from incorrect thread"

Has anyone example code or tutorial when and where I should call methods ?

Upvotes: 1

Views: 4147

Answers (1)

Jake Cronin
Jake Cronin

Reputation: 1062

A realm, as well as most objects in that realm, can only be accessed from the thread that this realm was created on (i.e. the thread on which you did something like let realm = Realm()).

So when you create a realm let realm = try Realm() on 'thread A', you can only access this realm from 'thread A'. Otherwise, you get a RLMException.

Likewise for most objects, if you grab it from this realm on 'thread A', for example: var myCars = realm.objects(Car.self), then you can only use your myCars object on 'thread A'.

A quick fix, but definitely not the best approach for a production quality app, is to just throw everything onto the main queue. This ensures that all of your realm stuff occurs on the same thread, but the downfall is that it can significantly slow down your app if you are doing some heavy lifting. In swift 3, you do this by:

DispatchQueue.main.async{
    do{
        //your stuff.
        //ex:
        let realm = try Realm()
        myCars = try realm.objects(Car.self)
        if myCars != nil{
            try realm.write{
                for car in myCars!{
                    car.drive()
                }
            }
        }
    }catch{
        print(error)
    }
}

A much better solution is to use a background queue, and then go back to the main queue when you need to update. You can create a background queue like this:

let myRealmQueue = DispatchQueue(label: "realmQueue", qos: .background)

And then do your realm stuff on this queue:

myRealmQueue.async{
    do{
        //Do your realm stuff in this queue.
        let realm = try Realm()
        myCars = try realm.objects(Car.self)
        if myCars != nil{
            let numberOfCars = myCars.count
            //return to main queue to update UI
            DispatchQueue.main.async{
                numberOfCarsLabel.text = numberOfCars
            }
        }
    }catch{
        print(error)
    }
}

If you are not very familiar with threading in swift, I recommend you spend at least an hour or two on google to familiarize yourself with best practices. Chances are you'll find a better solution than the one I've provided.

Upvotes: 7

Related Questions