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
相关产品推荐
相关产品推荐

