【发布时间】:2019-12-20 08:35:21
【问题描述】:
我正在尝试使用 CoreData 和 QueryGenerationTokens 工作的示例项目。该项目的本质是将更改提交到计时器上的背景上下文(模拟来自服务器的更改),直到在 UI 上执行操作(例如,按下按钮)才应该显示。
目前,我在后台上下文中保存了更改(每 5 秒添加一个实体并保存)并且它们自动进入视图上下文(如预期的那样,.automaticallyMergesChangesFromParent 设置为 true)。 哪里出了问题,我会在当前查询生成令牌发生任何这些更改之前固定视图上下文。我希望视图不会随着添加的背景项目而更新,但它会随着它们一起更新。所以看起来查询生成令牌没有效果?
我想到的一些可能的问题:
- 我从 Apple 发现的唯一 example 没有显示他们将其与获取的结果控制器一起使用(我在 SwiftUI 中使用
@FetchRequest,我几乎完全可以肯定它本质上是相同的),所以这可能会产生影响? - .automaticallyMergeChangesFromParent 不应使用,我应该尝试合并策略,但这似乎也不起作用,从概念上讲,查询生成令牌似乎应该与此一起使用并固定到生成,无论合并。
视图代码 - 处理从视图上下文加载数据
// Environment object before fetch request necessary
// Passed in wherever main view is instantiated through .environment()
@Environment(\.managedObjectContext) var managedObjectContext
// Acts as fetched results controller, loading data automatically into items upon the managedObjectContext updating
// ExampleCoreDataEntity.retrieveItemsFetchRequest() is an extension method on the entity to easily get a fetch request for the type with sorting
@FetchRequest(fetchRequest: ExampleCoreDataEntity.retrieveItemsFetchRequest()) var items: FetchedResults<ExampleCoreDataEntity>
var body: some View {
NavigationView {
// Button to refresh and bring in changes
Button(
action: {
do {
try self.managedObjectContext.setQueryGenerationFrom(.current)
self.managedObjectContext.refreshAllObjects()
} catch {
print(error.localizedDescription)
}
},
label: { Image(systemName: "arrow.clockwise") }
)
// Creates a table of items sorted by the entity itself (entities conform to Hashable)
List(self.items, id: \.self) { item in
Text(item.name ?? "")
}
}
}
SceneDelegate 中的代码(启动 SwiftUI 应用程序的地方)我还初始化了 CoreData 所需的内容:
// Setup and pass in environment of managed object context to main view
// via extension on persistent container that sets up CoreData stack
let managedObjectContext = NSPersistentContainer.shared.viewContext
do {
try managedObjectContext.setQueryGenerationFrom(.current)
} catch {
print(error.localizedDescription)
}
let view = MainView().environment(\.managedObjectContext, managedObjectContext)
// Setup background adding
timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(backgroundCode), userInfo: nil, repeats: true)
// Setup window and pass in main view
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: view)
后台添加数据功能:
@objc func backgroundCode() {
ExampleCoreDataEntity.create(names: ["background object"], in: backgroundContext, shouldSave: true)
}
NSPersistentContainer 的设置:
extension NSPersistentContainer {
private struct SharedContainerStorage {
static let container: NSPersistentContainer = {
let container = NSPersistentContainer(name: "Core_Data_Exploration")
container.loadPersistentStores { (description, error) in
guard error == nil else {
assertionFailure("CoreData: Unresolved error \(error!.localizedDescription)")
return
}
container.viewContext.automaticallyMergesChangesFromParent = true
}
return container
}()
}
static var shared: NSPersistentContainer {
return SharedContainerStorage.container
}
}
在实体上创建/读取/更新/删除函数:
extension ExampleCoreDataEntity {
static func retrieveItemsFetchRequest() -> NSFetchRequest<ExampleCoreDataEntity> {
let request: NSFetchRequest<ExampleCoreDataEntity> = ExampleCoreDataEntity.fetchRequest()
request.sortDescriptors = [NSSortDescriptor(keyPath: \ExampleCoreDataEntity.creationDate, ascending: false)]
return request
}
static func create(names: [String], in context: NSManagedObjectContext, shouldSave save: Bool = false) {
context.perform {
names.forEach { name in
let item = ExampleCoreDataEntity(context: context)
item.name = name
item.creationDate = Date()
item.identifier = UUID()
}
do {
if save {
try context.save()
}
} catch {
// print error
}
}
}
func delete(in context: NSManagedObjectContext, shouldSave save: Bool = false) {
context.perform {
let name = self.name ?? "an item"
context.delete(context.object(with: self.objectID))
do {
if save {
try context.save()
}
} catch {
// print error
}
}
}
}
【问题讨论】: