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

时间:2017-01-21 16:33:55

标签: ios swift realm

我注意到访问realm对象时遇到了很多问题,我认为我的解决方案就是解决这个问题。

所以我写了这样简单的帮助方法:

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

我认为完成块会很好,因为每次我写对象或更新它时,我都会使用上面的方法。

不幸的是我收到了错误:

libc++abi.dylib: terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread.

4 个答案:

答案 0 :(得分:20)

RealmObject的实例是线程包含的。它们不能在线程之间传递,否则会发生异常。

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

就像Dave说的那样,每次调用该方法时都会创建一个新的调度队列。但是为了扩展这一点,iOS也无法保证在同一个线程上始终会调用单个队列。

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

要更新特定对象,您可以使用the new ThreadSafeReference feature重新访问后台线程上的同一对象。

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

答案 1 :(得分:6)

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

DispatchQueue(name:"")是初始化程序,而不是查找。如果要确保始终位于同一队列中,则需要存储对该队列的引用并将其分派给它。

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

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

通常在您在其他线程中对其进行初始化并尝试从其他线程进行访问或修改时会发生这种情况。只需放置一个调试器,看看它初始化了哪个线程,然后尝试使用同一线程即可。

相关问题