Realm-cocoa: Fetching data in background and dispatch to main thread

Created on 10 Jun 2017  路  7Comments  路  Source: realm/realm-cocoa

I need to load data from realm in the background thread (because I need to set the data inside UITableViewCell and it would make the View laggy if I load them in the main thread) but the problem is, that there is no way to dispatch the fetched data to the main thread.

If you do the following for example:

DispatchQueue.global(qos: .background).async {
    let realm = try! Realm();

    self.tableEntries = realm.object(ofType: MY_OBJECT.self);

    DispatchQueue.main.async {
        self.tableView.reloadData();
    }
}

I will always get the Realm accessed from incorrect thread exception. But I cant find a way to prevent that.
How am I supposed to solve this?

Most helpful comment

You can use Realm Collection Notifications to run a query on a background thread and then receive the result on the main thread:

class ViewController {
    var results: Results<ObjectType>?
    var token: NotificationToken?

    func setUp() {
        let realm = try! Realm()
        token = realm.objects(ObjectType.self).filter("...").addNotificationBlock { changes in
            switch changes {
            case .initial(let collection):
                self.results = collection
                self.tableView.reloadData()
                break
            case .update:
                self.tableView.reloadData()
                break
            case .error(let err):
                fatalError("\(err)")
                break
            }
        }
    }
}

The notification block is called on the same thread as it is add on, while the actual running of the query is done on a separate worker thread.

All 7 comments

You face this error because the realm objects you received are being accessed on another thread. This is evident from your line:
self.tableEntries = realm.object(ofType: MY_OBJECT.self);

Accessing tableEntries on some other thread will cause this problem to occur.

Yes Im aware of that. Im asking for a solution. But I guess there is no, since there is #1097 open for over 3 years now and no progress is happening.

One solution could be that you form a struct from your Realm Object's result and use that struct instead, for your tableview.

The objects returning to the main thread need to be changeable and deletable in the realm.

I know it's extra work but you can write edit/delete methods that achieve that, based on a property of the object.

You can use Realm Collection Notifications to run a query on a background thread and then receive the result on the main thread:

class ViewController {
    var results: Results<ObjectType>?
    var token: NotificationToken?

    func setUp() {
        let realm = try! Realm()
        token = realm.objects(ObjectType.self).filter("...").addNotificationBlock { changes in
            switch changes {
            case .initial(let collection):
                self.results = collection
                self.tableView.reloadData()
                break
            case .update:
                self.tableView.reloadData()
                break
            case .error(let err):
                fatalError("\(err)")
                break
            }
        }
    }
}

The notification block is called on the same thread as it is add on, while the actual running of the query is done on a separate worker thread.

I find the realm object take notes the thread, when we use the object at child thread, then it will happen "Realm accessed from incorrect thread", this issue is solved ?????????????????

Was this page helpful?
0 / 5 - 0 ratings

Related issues

carvalho-oak picture carvalho-oak  路  3Comments

menhui222 picture menhui222  路  3Comments

matteodanelli picture matteodanelli  路  3Comments

i-schuetz picture i-schuetz  路  3Comments

dmorrow picture dmorrow  路  3Comments