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

Realm accessed from incorrect thread - 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()
        }
    } 
 }

然后我收到错误

terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread.

我该如何解决这个问题?

似乎写入发生在与最初访问对象不同的线程上。您应该能够通过传递 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对象不能被不同的线程访问意味着,一个线程中定义的一个Realm实例不能被不同的线程访问。我们实际上应该做的是我们需要为每个线程拥有不同的领域实例。

例如。让我们看看下面的例子单击按钮后,我们在后台线程中异步向数据库中插入 50 条记录,并在主线程中添加通知块以更新计数标签中的人数。每个线程(主线程和后台线程)都有自己的领域对象实例来访问领域数据库。因为 Realm 数据库通过使 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 上解析此引用 Realm.resolve(_:)。
  4. 像往常一样使用返回的对象。

你还可以获得

Realm accessed from incorrect thread

如果您尝试按获取的项目写入