swift - 如何在 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 的情况下合并更改?
解决方案
我在 AppDelegate 中测试了一个从通知对象获取上下文的新函数,然后在该上下文的线程上异步执行 mergeChanges。这至少不会阻塞用户界面。在未来的一些测试之后,我会看看变化是否仍然存在。
@objc func handleBackgroundCoreDataChangeInMainManagedContext(notification: Notification){
if let moc2 = notification.object as? NSManagedObjectContext {
moc2.perform {
moc2.mergeChanges(fromContextDidSave: notification)
}
}
}
推荐阅读
- java - 无法在此处初始化数组
- php - 我将数据从索引转换为进程时出错“类 mysqli_result 的对象无法转换为 int”
- c# - WPF菜单不停留在顶部
- c# - 每次测试都会调用 OneTimesetup,我认为 OneTimesetup 就像 BeforeSuite,TestNG 注释
- c# - ConfigureAwait(false) 维护线程身份验证,但默认情况下不
- php - 如何使用 docker-compose 通过 nginx 路由我的 php 服务器?
- julia - 使用 `Int((n+1)/2)`、`round(Int, (n+1)/2)` 或 `Int((n+1)//2)` 哪个更好?
- java - 如果 Android Studio 的 for 循环忽略嵌套
- amazon-web-services - 限制 amazon-s3 仅访问 android 应用程序
- python - 我正在更改一个变量,但是如何在函数结束时返回它的原始状态?