floorish
floorish

Reputation: 718

Reading updated Realm ThreadSafeReference on background queue

According to the Realm docs on threading:

When you initially open a Realm on a thread, its state will be based off the most recent successful write commit

And:

Failing to resolve a ThreadSafeReference will result in the source version of the Realm being pinned until the reference is deallocated.

This gives a bit confusing results when used together. If a ThreadSafeReference is asynchronously resolved on a background queue it shows old (pinned) values. But if a ThreadSafeReference is synchronously resolved it shows updated values.

Let's say I have a simple Realm Object: MyObject with a single name property:

// setup, create object with name: "a"
let queue = DispatchQueue(label: "com.app.my", qos: .default, attributes: [])
let obj = MyObject(name: "a")
try realm.write { realm.add(obj) }

// get reference (deliberately created before update)
let ref = ThreadSafeReference(to: obj)

// update name to "b" (main queue, or .sync on other queue)
try realm.write {
    obj.name = "b"
}

// async resolve on background thread
queue.async {
    let r = try! Realm()
    let o = r.resolve(ref)!

    XCTAssertEqual("b", o.name) // fails, o.name == "a"

    r.refresh()

    XCTAssertEqual("b", o.name) // succeeds
}

Compared to:

// setup, create object with name: "a"
let queue = DispatchQueue(label: "com.app.my", qos: .default, attributes: [])
let obj = MyObject(name: "a")
try realm.write { realm.add(obj) }

// get reference (deliberately created before update)
let ref = ThreadSafeReference(to: obj)

// update name to "b" (main queue, or .sync on other queue)
try realm.write {
    obj.name = "b"
}

// sync resolve on background thread
queue.sync {
    let r = try! Realm()
    let o = r.resolve(ref)!

    XCTAssertEqual("b", o.name) // succeeds
}

If queue.sync is used instead of queue.async the Realm doesn't need to be refreshed manually, and the resolved reference immediately shows the updated "b" name. This is also the case when the realm is queried for MyObject instead of resolving the reference.

So what exactly is the behaviour of ThreadSafeReferences? It looks like it sometimes keeps pinned values, but sometimes doesn't. Why is it necessary to refresh the Realm in this case when it should be based on the 'most recent successful write commit'?

Upvotes: 1

Views: 493

Answers (1)

mykolaj
mykolaj

Reputation: 974

Seen the same issue some time ago, and recently found the answer why this happens:

[Quote:]

... we added new object on main thread Realm and at the same time we are polling on background thread to get the changes but background Thread Realm was not notified even its autorefresh property is true and the answer is as documented “background threads do not have an active run loop and you will need to manually call refresh() in order to update to the latest version, even if autorefresh is set to true.”

[End of quote]

You can find the original post here by following this link

So the answer is that in order to see changes we have to manually call Realm.refresh() function if we operate in thread which does not have a run loop

Upvotes: 1

Related Questions