如何在SwiftData中使用后台上下文?求CoreData automaticallyMergesChangesFromParent等效方案
我正在使用SwiftData重构模型层,目前模型与容器均已正常运行,希望开始使用后台上下文执行CRUD操作。
以下是我的容器配置代码:
@Observable class OhMyModelController { public static var shared = OhMyModelController() let modelContainer: ModelContainer let workContext: ModelContext public init() { let schema: Schema = Schema([TestModelClass.self]) let inMemory: Bool = Configuration.mode == .unitTesting ? true : false let modelConfiguration = ModelConfiguration(Configuration.mode.rawValue, inMemory: inMemory, readOnly: false, sharedAppContainerIdentifier: Configuration.appGroupName, cloudKitContainerIdentifier: Configuration.cloudKitContainerIdentifier) self.modelContainer = try! ModelContainer(for: schema, configurations: [modelConfiguration]) self.workContext = ModelContext(self.modelContainer) } }
增删操作的实现如下(可使用环境中的主上下文或控制器中的workContext):
public func create(_ context: ModelContext?) { let contextToUse: ModelContext = context != nil ? context! : workContext contextToUse.insert(object: TestModelClass(name: "Test")) try? contextToUse.save() } public func delete(_ test: TestModelClass, on context: ModelContext?) { let contextToUse: ModelContext = context != nil ? context! : workContext contextToUse.delete(test) try? contextToUse.save() }
测试视图代码:
struct SwiftDataTest: View { @Environment(\.modelController) var modelController: OhMyModelController @Environment(\.modelContext) var modelContext: ModelContext @Query() var tests: [TestModelClass] var body: some View { VStack { List { ForEach(tests) { test in Text(test.name) .onTapGesture(perform: { modelController.delete(test, on: modelContext) }) } } Button(action: { modelController.create(modelContext) }, label: { Text("Testers will test!") }) } } }
目前使用@Environment的modelContext与workContext执行增删操作均有效,但两者无法自动同步数据。请问SwiftData中是否有CoreData的automaticallyMergesChangesFromParent等效功能?难道必须通过保存通知手动追踪并合并更改吗?
SwiftData确实提供了类似CoreData中automaticallyMergesChangesFromParent的自动同步能力,无需手动追踪通知,只需正确配置上下文即可:
1. 开启上下文自动合并
创建ModelContext后,手动开启自动合并属性并设置合并策略,就能让上下文自动同步容器内其他上下文的变更:
self.workContext = ModelContext(self.modelContainer) // 开启自动合并父容器的变更 workContext.automaticallyMergesChangesFromParent = true // 设置合并策略,可根据需求选择不同策略,这里优先保留本地修改 workContext.mergePolicy = ModelMergePolicy.mergeByPropertyStoreTrump
环境中的主上下文(@Environment(\.modelContext))默认已开启自动合并,无需额外配置。
2. 优化后台上下文操作
后台上下文的操作建议放在异步队列执行,避免阻塞UI线程,比如用Task.detached包裹保存逻辑:
public func create(_ context: ModelContext?) { Task.detached { [weak self] in guard let self = self else { return } let contextToUse = context ?? self.workContext contextToUse.insert(object: TestModelClass(name: "Test")) try? contextToUse.save() } }
3. @Query的自动刷新
只要上下文开启了自动合并,@Query会自动感知容器内的变更并刷新视图,无需手动处理UI更新逻辑。
总结
只要正确开启automaticallyMergesChangesFromParent并配置合并策略,多个上下文就能自动同步数据,不需要手动监听保存通知。只有当你需要自定义合并逻辑时,才需要手动处理通知。
内容的提问来源于stack exchange,提问作者Brian M

