You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 21:25:00