ios 从错误的线程访问领域 - 再次

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/41781775/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 11:05:20  来源:igfitidea点击:

Realm accessed from incorrect thread - again

iosswiftrealm

提问by Tajnero

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.

回答by TiM

Instances of Realmand Objectare thread-contained. They cannot be passed between threads or that exception will occur.

的情况下,RealmObject是线程遏制。它们不能在线程之间传递,否则会发生异常。

Since you're passing the completionblock 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.

由于您在completion创建队列的同时将块本身传递给后台队列(正如 Dave Weston 所说),因此该块内的任何 Realm 对象肯定不会在同一线程上创建,这可以解释这一点错误。

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.

就像 Dave 所说的那样,每次调用该方法时都会创建一个新的调度队列。但要扩展一下,iOS 也不能保证在同一线程上始终调用单个队列。

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 Realmon a per-thread basis, so there's very little overhead involved with calling Realm()multiple times.

因此,Realm 的最佳实践是每次要在该线程上执行新操作时在同一线程上重新创建 Realm 对象。Realm 在内部缓存Realm每个线程的实例,因此Realm()多次调用所涉及的开销非常小。

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

要更新特定对象,您可以使用ThreadSafeReference功能在后台线程上重新访问同一对象。

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"
  }
}

回答by Dave Weston

Your method creates a new DispatchQueueevery time you call it.

您的方法DispatchQueue每次调用时都会创建一个新方法。

DispatchQueue(name:"")is an initializer, not a lookup. If you want to make sure you're always on the same queue, you'll need to store a reference to that queue and dispatch to it.

DispatchQueue(name:"")是初始化程序,而不是查找。如果你想确保你总是在同一个队列中,你需要存储对该队列的引用并分派给它。

You should create the queue when you setup the Realm, and store it as a property of the class that does the setup.

您应该在设置 Realm 时创建队列,并将其存储为进行设置的类的属性。

回答by Kowboj

Perhaps it helps someone (as I spent a few hours looking for a solution)

也许它可以帮助某人(因为我花了几个小时寻找解决方案)

In my case, I had a crash in background mapping of JSON to a model (which imported ObjectMapper_Realm). At the same time there was an instance of realm allocated on main thread.

就我而言,我在将 JSON 背景映射到模型(导入 ObjectMapper_Realm)时发生了崩溃。同时在主线程上分配了一个领域的实例。

回答by MD Aslam Ansari

Generally it happens when you initialised it in different thread and trying to access or modify from different thread. Just put a debugger to see which thread it was initialised and try to use same thread.

通常,当您在不同的线程中初始化它并尝试从不同的线程访问或修改时,会发生这种情况。只需放置一个调试器来查看它初始化的线程并尝试使用相同的线程。