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

为何SwiftData未显式插入却自动创建Line实体?

SwiftData自动插入关联实体的问题分析与解决

问题原因

SwiftData的@Relationship属性会自动追踪关联实体的状态。当你创建一个Line实例并将其关联到已被插入并持久化的Production实例时,SwiftData会自动将这个Line插入到当前的modelContext中——哪怕你只是把它存在本地@State数组里,没有显式调用modelContext.insert()。

在你的代码中,TextEnterScriptView接收的production是已经在ContentView中被插入到上下文并保存过的实体。每次在TextEditor输入时,你创建Line(content: "test line", production: production),将这个新Line的production属性指向已持久化的Production,SwiftData会通过关联关系自动将该Line加入上下文,导致ScriptView的@Query查询到新实体并显示。

另外,你的ScriptView中的@Query没有添加过滤条件,会查询所有Line实体,这也会导致所有自动插入的Line都被展示出来。

解决方案

1. 临时实体不关联持久化对象,确认后再保存

修改TextEnterScriptView,先创建不关联production的临时Line,等用户点击"Done"确认后,再关联并插入到上下文:

struct TextEnterScriptView: View {
    @Environment(\.dismiss) var dismiss
    @Environment(\.modelContext) var modelContext
    @State private var text = ""
    @State private var lines: [Line] = []
    let production: Production
    
    var body: some View {
        NavigationStack {
            TextEditor(text: $text)
                .onChange(of: text, initial: false) {
                    // 创建临时Line,不关联production
                    lines = [Line(content: "test line", production: nil)]
                }
                .toolbar {
                    Button("Done") {
                        // 用户确认后,关联production并插入上下文
                        lines.forEach { line in
                            line.production = production
                            modelContext.insert(line)
                        }
                        // 保存上下文
                        do {
                            try modelContext.save()
                        } catch {
                            print(error)
                        }
                        dismiss()
                    }
                }
        }
    }
}

2. 给ScriptView的@Query添加过滤条件

修改ScriptView,让@Query只查询当前production关联的Line,避免展示所有实体:

struct ScriptView: View {
    let production: Production
    @Query private var lines: [Line]
    @State private var isShowingSheet: Bool = false
    
    // 初始化Query时添加过滤条件
    init(production: Production) {
        self.production = production
        _lines = Query(filter: #Predicate<Line> { $0.production == production })
    }
    
    var body: some View {
        List {
            ForEach(lines) { line in
                Text(line.content)
            }
        }
        .toolbar {
            Button("Show Sheet") {
                isShowingSheet.toggle()
            }
        }
        .sheet(isPresented: $isShowingSheet) {
            TextEnterScriptView(production: production)
        }
    }
}

额外说明

SwiftData的自动关联插入是设计特性,目的是简化关联实体的管理。如果需要临时创建实体用于编辑但不立即持久化,核心原则是不要将临时实体关联到已在上下文中的持久化实体,直到确认要保存为止。

内容的提问来源于stack exchange,提问作者The-Wolf

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 10:46:18