Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
941 views
in Technique[技术] by (71.8m points)

ios - Realm accessed from incorrect thread - again

I noticed many problems with accessing realm object, and I thought that my solution would be solving that.

So I have written simple helping method like this:

public func write(completion: @escaping (Realm) -> ()) {
    DispatchQueue(label: "realm").async {
        if let realm = try? Realm() {
            try? realm.write {
                completion(realm)
            }
        }
    }
}

I thought that completion block will be fine, because everytime I write object or update it, I use this method above.

Unfortunately I'm getting error:

libc++abi.dylib: terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread.
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Instances of Realm and Object are thread-contained. They cannot be passed between threads or that exception will occur.

Since you're passing the completion block itself to the background queue at the same time the queue is being created (As Dave Weston said), any Realm objects inside that block will most certainly not have been created on the same thread, which would explain this error.

Like Dave said, you're creating a new dispatch queue every time you call that method. But to expand upon that, there's also no guarantee by iOS that a single queue will be consistently called on the same thread.

As such, best practice with Realm is to recreate your Realm objects on the same thread each time you want to perform a new operation on that thread. Realm internally caches instances of Realm on a per-thread basis, so there's very little overhead involved with calling Realm() multiple times.

To update a specific object, you can use the new ThreadSafeReference feature to re-access the same object on a background thread.

let realm = try! Realm()
let person = Person(name: "Jane") // no primary key required
try! realm.write {
  realm.add(person)
}
let personRef = ThreadSafeReference(to: person)
DispatchQueue(label: "com.example.myApp.bg").async {
  let realm = try! Realm()
  guard let person = realm.resolve(personRef) else {
    return // person was deleted
  }
  try! realm.write {
    person.name = "Jane Doe"
  }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...