领域从错误的线程访问 – 再次
我注意到访问领域对象有很多问题,我认为我的解决方案就是解决这个问题。
所以我写了这样简单的帮助方法:
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.
Realm
和Object
实例是线程包含的。 它们不能在线程之间传递,否则将发生exception。
由于您在创建队列的同时将completion
块本身传递给后台队列(如Dave Weston所说),该块内的任何Realm对象肯定不会在同一个线程上创建,这可以解释这个错误。
就像Dave说的那样,每次调用该方法时都会创建一个新的调度队列。 但是为了扩展它,iOS也无法保证在同一个线程上一致地调用单个队列。
因此,Realm的最佳实践是每次要在该线程上执行新操作时在同一线程上重新创建Realm对象。 Realm在每个线程的基础上内部缓存Realm的实例,因此多次调用Realm()
涉及的开销很小。
要更新特定对象,可以使用新的ThreadSafeReference
function在后台线程上重新访问同一对象。
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" } }
每次调用它时,您的方法都会创建一个新的DispatchQueue
。
DispatchQueue(name:"")
是初始化程序,而不是查找。 如果要确保始终位于同一队列中,则需要存储对该队列的引用并将其分派给它。
您应该在设置Realm时创建队列,并将其存储为执行安装的类的属性。
- 如何在animateTransition期间获取ToViewController中子视图的框架:?
- 在UIWebView中检测单击,但仍支持文本select和链接
- Sqlite3更新查询不工作在iOS应用程序
- ios AVCaptureVideoPreviewLayer捕获当前图像
- IOS:在另一个类中调用一个方法
- UIPinchGestureRecognizer。 放大手指的位置,不仅中心
- Xcode 7如何刷新configuration文件?
- UITableView DidSelectRowAtIndexPath?
- 如何使用GStreamer在iOS 8中使用AVSampleBufferDisplayLayer进行RTP H264stream处理?