首页 > 解决方案 > 如何在 Swift 中合并核心数据背景上下文和主上下文之间的更改

问题描述

我有一个 MacOS 应用程序,可以将数据从 CSV 导入核心数据。由于这可能是一个长时间运行的过程,我选择在后台线程中进行导入,这样我就可以使用导入进度更新 UI。因此,为了避免在将更改保存到持久存储时出现乐观锁定失败,我在后台上下文和主上下文之间合并保存更改。

我认为我没有正确处理合并更改,因为当我在后台上下文中调用 save 时,它​​会调用一个阻塞 UI 的合并更改函数。有没有办法在不阻塞 UI 的情况下合并上下文之间的更改?

以下是我创建称为 moc2 的背景上下文的方法:

let app = NSApplication.shared.delegate as! AppDelegate
let container = app.persistentContainer
        container.performBackgroundTask(){ (moc2) in
NotificationCenter.default.addObserver(self.app, selector: #selector(self.app.handleBackgroundCoreDataChangeInMainManagedContext(notification:)), name: NSNotification.Name.NSManagedObjectContextDidSave, object: moc2)
//perform import...
self.save(moc2: moc2)
}

和保存功能:

func save(moc2: NSManagedObjectContext){
    do {
        try moc2.save()
    } catch {
        print(error)
    }
}

这是 AppDelegate 中的合并更改选择器:

@objc func handleBackgroundCoreDataChangeInMainManagedContext(notification: Notification){
    DispatchQueue.main.async {
        self.managedObjectContext?.mergeChanges(fromContextDidSave: notification)
    }
}

有没有办法使用 DispatchQueue.main.async 在不阻塞 UI 的情况下合并更改?

标签: swiftmacoscocoacore-data

解决方案


我在 AppDelegate 中测试了一个从通知对象获取上下文的新函数,然后在该上下文的线程上异步执行 mergeChanges。这至少不会阻塞用户界面。在未来的一些测试之后,我会看看变化是否仍然存在。

@objc func handleBackgroundCoreDataChangeInMainManagedContext(notification: Notification){
    if let moc2 = notification.object as? NSManagedObjectContext {
        moc2.perform {
            moc2.mergeChanges(fromContextDidSave: notification)
        }
    }
}

推荐阅读