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

SwiftData三层关联在SwiftUI预览中崩溃问题求助

问题描述

我的Core Data模型存在三层一对多关联:Parent(一) -> Child(多) -> GrandChild(多)。该设置在模拟器中运行正常,但取消注释添加GrandChild的代码后,SwiftUI预览会崩溃,模拟器则不受影响。

相关代码

App入口代码

@main
struct Test_ModelApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: [Parent.self, Child.self, GrandChild.self])
    }
}

Core Data模型代码

@Model
final class Parent {
    var name: String
    
    @Relationship(deleteRule: .cascade, inverse: \Child.parent)
    var children: [Child]
    
    init() {
        self.name = "Parent"
    }
}

@Model
final class Child {
    var name: String
    
    var parent: Parent?
    
    @Relationship(deleteRule: .cascade, inverse: \GrandChild.child)
    var grandChildren: [GrandChild]
    
    init(parent: Parent) {
        self.name = "Child"
        self.parent = parent
    }
}

@Model
final class GrandChild {
    var name: String
    
    var child: Child?
    
    init(child: Child) {
        self.name = "Grandchild"
        self.child = child
    }
}

测试视图代码

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var parents: [Parent]
    
    var body: some View {
        VStack {
            Button("Add parent and children") {
                let parent = Parent()
                modelContext.insert(parent)
                
                let child1 = Child(parent: parent)
                let child2 = Child(parent: parent)
                modelContext.insert(child1)
                modelContext.insert(child2)
                
//                for child in parent.children {
//                    let grandChild1 = GrandChild(child: child)
//                    let grandChild2 = GrandChild(child: child)
//                    modelContext.insert(grandChild1)
//                    modelContext.insert(grandChild2)
//                }
            }
            
            ForEach(parents) { parent in
                HStack {
                    Text(parent.name)
                    Button("Remove") {
                        modelContext.delete(parent)
                        do {
                            try modelContext.save()
                        } catch {
                            print(error.localizedDescription)
                        }
                    }
                }
                ForEach(parent.children) { child in
                    Text(child.name)
                    ForEach(child.grandChildren) { grandChild in
                        Text(grandChild.name)
                    }
                }
            }
        }
        .padding()
    }
}

#Preview {
    ContentView()
        .modelContainer(for: [Parent.self, Child.self, GrandChild.self], inMemory: true)
}

崩溃原因

取消注释的代码中,你尝试遍历parent.children来创建孙辈,但刚将Child实例插入上下文后,Core Data不会立即同步更新Parent的children集合——这个集合的内存镜像要等到上下文刷新(比如执行save操作,或Core Data内部变更通知触发后)才会更新。在SwiftUI预览的内存容器环境中,这种未同步的状态会触发Core Data内部一致性错误,进而引发崩溃;而模拟器运行时,上下文的刷新时机或环境容错性更高,因此没有表现出问题。

解决方案

直接使用你已经创建好的child1和child2实例来创建GrandChild,不需要通过parent.children遍历:

Button("Add parent and children") {
    let parent = Parent()
    modelContext.insert(parent)
    
    let child1 = Child(parent: parent)
    let child2 = Child(parent: parent)
    modelContext.insert(child1)
    modelContext.insert(child2)
    
    // 直接用已创建的child实例,跳过遍历parent.children
    let grandChild1 = GrandChild(child: child1)
    let grandChild2 = GrandChild(child: child1)
    let grandChild3 = GrandChild(child: child2)
    let grandChild4 = GrandChild(child: child2)
    
    modelContext.insert(grandChild1)
    modelContext.insert(grandChild2)
    modelContext.insert(grandChild3)
    modelContext.insert(grandChild4)
}

如果后续需要批量处理已存在的Child实例,建议先调用try modelContext.save()同步上下文,再遍历parent.children,确保集合数据是最新的。


内容的提问来源于stack exchange,提问作者HugoLXO

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:49:57