Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can we generate Realm results in background queue and use it on main thread

Tags:

ios

swift

realm

I'm starting using Realm recently, I'm not sure if my use case is valid:

Normally, when reading a lot of data from DB, I want to put it in a background queue so it will async get the data and later use it on main thread.

For example, I want to fetch several results based on city:

    private var results: [Results<SomeObject>?] = []
    autoreleasepool {
        DispatchQueue(label: "background").async {
            [unowned self] in
            do
            {
                let realm = try Realm()
                for i in 1...City.count
                {
                    self.results.append(realm.objects(SomeObject.self).filter("city=\(i)"))
                }
            }
            catch
            {
                NSLog("Failed to open Realm instance on background qeueue")
            }
        }
    }

And later use results to update my chart:

cell.setChartData(ChartDataFactory.createCombinedData(from: results[0]))

However if I apply this model for Realm, I'm getting error like

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

I understand I must use realm for each thread, and I can do this by reading realm on main thread, but I don't want the realm query block my main thread.

is there any way I can achieve my goal? e.g. reading realm in a background queue and access the results from another thread, while keeping the auto-refresh feature.

Thanks.

like image 860
Wingzero Avatar asked Jan 07 '18 03:01

Wingzero


1 Answers

Realm has built-in functionality for running a query on a background thread and delivering the results to the main thread by using Results.observe().

If you specifically need to perform expensive filtering logic that can't be expressed as a Realm query, you can manually pass an array of objects between threads using ThreadSafeReference.

As of 5.0, you can now construct the query on a background thread and receive notifications on the main thread using the on: parameter to observe():

DispatchQueue.global().async {
    let realm = try! Realm()
    let results = realm.objects(ObjectType.self).filter("property in %@", expensiveFunction(realm))
    self.token = results.observe(on: .main) { change in
        // do stuff with the results on the main thread
    }
}
like image 91
Thomas Goyne Avatar answered Oct 23 '22 07:10

Thomas Goyne