【问题标题】:Realm accessed from incorrect thread - Swift 3从不正确的线程访问领域 - Swift 3
【发布时间】:2016-12-23 16:01:22
【问题描述】:

在我的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: 从不正确的线程访问的领域。

我该如何解决这个问题?

【问题讨论】:

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


    【解决方案1】:

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

    【讨论】:

    • 啊,如果我想写,我不能从主线程(UI线程)读取?那我应该重新考虑使用线程吗?
    • 是的,当对象在线程之间传递时,Realm 会崩溃。这在我身上发生了很多:)
    • 如果我还必须进行额外的读取,您认为线程化写入会有什么优势吗?
    • 谢谢!这就是我们建议将工作卸载到后台线程的方式。您可以将taskId 设置为Realm 对象的主键,然后使用Realm.object(ofType:forPrimaryKey:) 在后台线程上检索对它的引用。
    • 作为一般经验法则,我们建议尽可能将持久的 Realm 写入事务卸载到后台线程。可以在写入过程中在其他线程上继续从 Realm 读取,但您需要注意,如果在后台正在进行写入并且您尝试在主线程上启动一个,这将阻塞您的 UI,直到后台操作已完成。
    【解决方案2】:

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

    首先,领域对象不能被不同的线程访问意味着,一个线程中定义的一个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))
                }
            }
    
        }
    }
    

    【讨论】:

      【解决方案3】:

      你也可以得到

      Realm accessed from incorrect thread
      

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

      【讨论】:

        【解决方案4】:

        您还可以使用 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. 通过调用解决目标领域上的此引用 领域.resolve(_:)。
        4. 像往常一样使用返回的对象。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-06
          • 2017-09-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-04
          相关资源
          最近更新 更多