从不正确的线程访问领域 – 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文档提供的步骤:
- 使用线程限制对象初始化ThreadSafeReference。
- 将ThreadSafeReference传递给目标线程或队列。
- 通过调用Realm.resolve(_ :)在目标Realm上解析此引用。
- 像往常一样使用返回的对象。