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

时间:2016-12-23 16:01:22

标签: ios swift multithreading realm grand-central-dispatch

getCustomerUsingID()的顶部是以下内容:

UITableViewController

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

let queue = DispatchQueue(label: "background")

然后我收到错误

  

以未捕获的类型异常终止   realm :: IncorrectThreadException:从错误的线程访问的域。

我该如何解决这个问题?

4 个答案:

答案 0 :(得分:4)

似乎写入发生在与最初访问对象不同的线程上。您应该能够通过传递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()
        }
    } 
 }

答案 1 :(得分:3)

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

首先,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))
            }
        }

    }
}

答案 2 :(得分:0)

您还可以使用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"
}

领域文档提供的步骤:

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

答案 3 :(得分:0)

还可以

Realm accessed from incorrect thread

如果您尝试按提取的项目进行书写