我遇到过2个CoreData演示项目,其中涉及交易历史。
两者都在使用
viewContext.setQueryGenerationFrom(.current)
当他们初始化 CoreData 堆栈时。
演示摘自 https://www.raywenderlich.com/14958063-modern-efficient-core-data
作者试图演示,如何利用交易历史记录,在批量插入后正确更新UI。
但是,尚不清楚
viewContext.setQueryGenerationFrom(.current)
试图解决什么问题。
文章的简要解释https://www.raywenderlich.com/14958063-modern-efficient-core-data并没有过多讲述
setQueryGenerationFrom
背后的想法。
您将视图上下文固定到最近的事务 通过调用 setQueryGenerationFrom(_:) 来实现持久存储。然而, 因为设置查询生成仅与 SQLite 兼容 store,只有当 inMemory 为 false 时才这样做。
演示摘自 https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud
它试图演示如何使用交易历史记录,以防止与CloudKit同步后的数据重复。
但是,目前还不清楚
viewContext.setQueryGenerationFrom(.current)
想要解决什么问题。
setQueryGenerationFrom
的想法背后没有给出太多解释。
无论我在 CoreData 堆栈中包含
viewContext.setQueryGenerationFrom(.current)
还是排除 viewContext.setQueryGenerationFrom(.current)
,我在这两种情况下都会得到相同的观察结果。
NSManagedObject
并调用 context.save
后,能够立即观察 UI 更新。NSManagedObject
并调用 context.save
后,能够立即观察 UI 更新。NSBatchUpdateRequest
操作并调用 mergeChanges
后,能够立即观察 UI 更新。NSBatchDeleteRequest
操作并调用 mergeChanges
后,能够立即观察 UI 更新。对于
setQueryGenerationFrom
所做的事情有一些很好的图形解释
https://cocoacasts.com/what-are-core-data-query- Generations
但是,我无法将其与
setQueryGenerationFrom
试图解决什么样的实际问题联系起来。
有谁知道,viewContext.setQueryGenerationFrom 在涉及事务历史的 CoreData 项目中试图解决什么问题? 如果有一个可靠的演示代码示例,以展示 setQueryGenerationFrom 解决了什么样的问题,我将不胜感激。谢谢。
它只是固定一些上下文快照,因此您接下来的所有查询都与该快照一起工作,而与固定时刻之后发生的情况无关。这就像从 GitHub 分离结账 - 每个人都可以继续,但你的工作没有沙箱。
这是一致性的保证,这可能是某些请求序列所需要的,在这些请求序列之间不应发生任何更改。
要固定,我们使用
viewContext.setQueryGenerationFrom(.current)
要取消固定并继续使用 kind-of-HEAD,我们使用
viewContext.setQueryGenerationFrom(nil)
更多说明参见Apple 的文章
以演示项目CoreDataCloudKitDemo为例,它是支持device1正在编辑帖子,device2删除帖子的情况。你可以找一下这段代码:
// The selected post was changed, and the user isn’t editing it.
// Show an alert, and go back to the main view to reload everything after the user taps reload.
let alert = UIAlertController(title: "Core Data CloudKit Alert",
message: "This post has been deleted by a peer!",
preferredStyle: .alert)
借助查询生成的魔力,在 device2 删除帖子后,我们将能够立即在正在编辑帖子的 device1 上弹出此警报。
在主列表视图上,没有问题,因为该项目可能只是以动画方式从列表中移出。问题在于详细信息视图、将显示什么以及如果用户编辑详细信息视图的值会发生什么。
在示例代码中,通常如下
container.viewContext.automaticallyMergesChangesFromParent = true
就像在详细信息视图中一样,通常我们会持有一个对象,一旦它被删除,该对象本身就会变得无效,访问它或属性会导致意外的行为。
它解决了如果你需要多次读取,数据不会在你脚下改变的问题,这里是一个例子,其中 context2 被固定,所以它在 context1 插入之前和之后的读取,返回相同的结果:
func testPinning(context1: NSManagedObjectContext) throws {
let context2 = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context2.persistentStoreCoordinator = context1.persistentStoreCoordinator
try context2.setQueryGenerationFrom(.current)
print("context2: pinned to current")
let authorName = "Charles Dickens"
let fr = Author.fetchRequest()
fr.predicate = NSPredicate(format: "name = %@", authorName)
let fetch = {
let results = try context1.fetch(fr)
let results2 = try context2.fetch(fr)
print("context1: fetched \(results.count), context2: fetched \(results2.count)")
}
try fetch()
let author = Author(context: context1)
author.name = authorName
try context1.save()
print("context1: inserted & saved")
try fetch()
try context2.setQueryGenerationFrom(.current)
print("context2: repinned to current")
try fetch()
}
输出是
context2: pinned to current
context1: fetched 0, context2: fetched 0
context1: inserted & saved
context1: fetched 1, context2: fetched 0 // because context2 is pinned it did not find the newly inserted author.
context2: repinned to current
context1: fetched 1, context2: fetched 1
正如你所看到的,因为 context2 被固定,在 context1 插入后,当 context2 再次获取时,它仍然没有结果。
您可能需要多次获取的原因是为了某些复杂的 UI,例如首先获取一个表,然后获取每一行,如果在第一次获取后后台上下文删除了一行,那么第二次获取将无法找到它。但是通过固定它可以找到它。