从不正确的线程访问领域 – Swift 3

在我的UITableViewController的顶部是以下内容:

 let queue = DispatchQueue(label: "background") 

删除任务时,执行以下操作:

 self.queue.async { autoreleasepool { let realm = try! Realm() realm.beginWrite() realm.delete(task) do { try realm.commitWrite() } catch let error { self.presentError() } } } 

然后我收到错误

以类型为realm :: IncorrectThreadException的未捕获exception终止:从不正确的线程访问Realm。

我怎么能解决这个问题?

似乎写入发生在与最初访问对象不同的线程上。 您应该能够通过传递task的id来修复它,并在执行写入之前使用它来从数据库中获取它(在异步块内)。

所以在顶部:

 var taskId = 0 // Set this accordingly 

然后像

 self.queue.async { autoreleasepool { let realm = try! Realm() let tempTask = // get task from Realm based on taskId realm.beginWrite() realm.delete(tempTask) do { try realm.commitWrite() } catch let error { self.presentError() } } } 

我们需要了解Realm Objects无法从不同的线程访问的事实 这意味着什么以及如何解决这个问题。

首先,realm对象无法从不同的线程手段访问,一个线程中定义的一个线程实例无法从不同的线程访问。 我们应该做的实际上是我们需要为每个线程提供不同的realm实例实例。

例如。 让我们看看下面的例子,例如我们在按钮点击后在后台线程中异步插入数据库中的50条记录,我们在主线程中添加通知块以更新计数标签中的人数。 每个线程(主要和后台)都有自己的领域对象实例来访问Realm数据库。 因为Realm Database通过使Realm的实例线程受限来实现线程安全。

 class Person: Object { dynamic var name = "" convenience init(_ name: String) { self.init() self.name = name } } override func viewDidAppear(_ animated: Bool) { let realmMain = try! Realm () self.people = realmMain.objects(Person.self) self.notification = self.people?.addNotificationBlock{ [weak self] changes in print("UI update needed") guard let countLabel = self?.countLabel else { return } countLabel.text = "Total People: \(String(describing: self?.people?.count))" } } @IBAction func addHandler(_ sender: Any) { print(#function) let backgroundQueue = DispatchQueue(label: "com.app.queue", qos: .background, target: nil) backgroundQueue.async { print("Dispatched to background queue") let realm = try! Realm() try! realm.write { for i in 1..<50 { let name = String(format: "rajan-%d", i) //print(#function, name) realm.add(Person(name)) } } } } 

您还可以使用ThreadSafe引用,这是在线程之间传递领域对象的特定方法:

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

Realm文档提供的步骤:

  1. 使用线程限制对象初始化ThreadSafeReference。
  2. 将ThreadSafeReference传递给目标线程或队列。
  3. 通过调用Realm.resolve(_ :)在目标Realm上解析此引用。
  4. 像往常一样使用返回的对象。