从不正确的线程访问的领域 - 再次
Posted
技术标签:
【中文标题】从不正确的线程访问的领域 - 再次【英文标题】:Realm accessed from incorrect thread - again 【发布时间】:2017-06-06 12:17:40 【问题描述】:我注意到访问领域对象有很多问题,我认为我的解决方案可以解决这个问题。
所以我写了这样简单的帮助方法:
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.
【问题讨论】:
那么completion
是做什么的?
【参考方案1】:
Realm
和 Object
的实例是线程包含的。它们不能在线程之间传递,否则会发生异常。
由于您在创建队列的同时将 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"
【讨论】:
嗯。什么?这听起来根本不对。您不能将标记应用于 Result 对象,而是从它们生成标记。这是一个关于 Realm 写入事务的问题,而不是查询。 别担心!对不起,简短的评论!我又在想这个。理论上,您可以使用通知块作为在与块相同的线程上捕获对象的一种方式,即使是从另一个线程更改时也是如此。但是你不会像使用线程引用那样拥有显式控制,你必须做一些事情来触发块。总之,一切顺利! :) 只是想澄清一下Realm
对象是按Thread
还是按DispatchQueue
缓存的?完全不同,因为DispatchQueue
访问线程池,每次可能得到不同的Thread
。
我只是仔细检查了代码以确认。是线程。在这种情况下,Realm 在内部直接使用 pthread
API。你可以在这里看到代码:github.com/realm/realm-cocoa/blob/…
我只是仔细检查了代码以确认。是线程。在这种情况下,Realm 在内部直接使用 pthread
API。你可以在这里看到代码:github.com/realm/realm-cocoa/blob/…【参考方案2】:
您的方法每次调用时都会创建一个新的DispatchQueue
。
DispatchQueue(name:"")
是一个初始化器,而不是一个查找器。如果您想确保始终在同一个队列中,则需要存储对该队列的引用并分派给它。
您应该在设置领域时创建队列,并将其存储为进行设置的类的属性。
【讨论】:
【参考方案3】:也许它可以帮助某人(因为我花了几个小时寻找解决方案)
就我而言,我在将 JSON 映射到模型(导入 ObjectMapper_Realm)时发生了崩溃。同时在主线程上分配了一个realm实例。
【讨论】:
【参考方案4】:通常当您在不同的线程中初始化它并尝试从不同的线程访问或修改时会发生这种情况。只需放置一个调试器来查看它初始化了哪个线程并尝试使用相同的线程。
【讨论】:
以上是关于从不正确的线程访问的领域 - 再次的主要内容,如果未能解决你的问题,请参考以下文章
在 IntentService 和 AsyncTask (Android) 之间使用共享代码时,领域“从不正确的线程访问”错误