问题描述
在 SwiftUI 视图中,默认情况下 FetchRequest
从 managedobjectContext
环境值中获取。如果视图想要提取到 isolated context 中,例如在不污染其他视图上下文的情况下进行可丢弃的编辑,它如何更改 FetchRequest
使用的上下文?
一种选择是将视图包装在创建隔离上下文的外部视图中,然后使用它调用包装的视图:
var body: some View {
WrappedView().environment(\.managedobjectContext,isolatedContext)
}
然而,这很乏味。您必须创建两个视图并通过包装器传递所有包装视图的参数。有没有更好的方法来告诉 FetchRequest
使用哪个上下文?
解决方法
如果您使用 Apple 作为初创公司提供的标准 PersistentController
,您可以尝试使用
.environment(\.managedObjectContext,privateContext)
您的 View
需要此属性才能使其工作。 @State
应该不是必需的,因为更改是通过其他方式(例如通知)在后台完成的。
let privateContext = PersistenceController.shared.container.newBackgroundContext()
调用 newBackgroundContext() 方法会导致持久性容器创建并返回一个新的 NSManagedObjectContext,concurrencyType 设置为 NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType。这个新上下文将直接与 NSPersistentStoreCoordinator 相关联,并设置为自动使用 NSManagedObjectContextDidSave 广播。
然后使用 Apple 的大部分示例代码对其进行测试。
struct SampleSharedCloudKitApp: App {
let privateContext = PersistenceController.shared.container.newBackgroundContext()
var body: some Scene {
WindowGroup {
VStack{
Text(privateContext.description) //Added this to match with ContentView
ContentView()
.environment(\.managedObjectContext,privateContext)
//Once you pass the privateContext here everything below it will have the privateContext
//You don't need to connect it with @FetchRequest by any other means
}
}
}
}
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp,ascending: true)],animation: .default)
private var items: FetchedResults<Item>
var body: some View {
List {
Text((items.first!.managedObjectContext!.concurrencyType == NSManagedObjectContextConcurrencyType.privateQueueConcurrencyType).description) //This shows true
Text(items.first!.managedObjectContext!.description)// This description matches the parent view
Text(viewContext.description)// This description matches the parent view
另外,需要注意的是你必须设置
container.viewContext.automaticallyMergesChangesFromParent = true
container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyStoreTrump
为了让主上下文显示在保存 privateContext
后所做的更改。我在 PersistenceController
闭包后立即将其放入 init
loadPersistentStores
。