Reputation: 718
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
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 istrue
and the answer is as documented “background threads do not have an active run loop and you will need to manually callrefresh()
in order to update to the latest version, even ifautorefresh
is set totrue
.”
[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