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

问题描述 投票:0回答:5

我注意到访问领域对象有很多问题,我认为我的解决方案可以解决这个问题。

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

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.
ios swift realm
5个回答
50
投票

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

由于您在创建队列的同时将

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

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

因此,Realm 的最佳实践是每次您想要在该线程上执行新操作时,在同一线程上重新创建 Realm 对象。 Realm 在每个线程的基础上在内部缓存

Realm
的实例,因此多次调用
Realm()
的开销非常小。

要更新特定对象,您可以使用新的

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

10
投票

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

DispatchQueue

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

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


3
投票

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

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


2
投票

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


0
投票

在我的领域中不要使用异步 只需使用同步

© www.soinside.com 2019 - 2024. All rights reserved.