SwiftData中使用@Relationship(.cascade)级联删除模型时崩溃的问题咨询
SwiftData中使用@Relationship(.cascade)级联删除模型时崩溃的问题咨询
我最近在SwiftData里测试@Relationship(deleteRule: .cascade)级联删除的特性,结果遇到了一个奇怪的崩溃,折腾了好半天没找到原因,来请教下各位大佬。
崩溃现象与错误信息
崩溃时抛出的错误信息如下:
Cannot fulfill future for PersistentIdentifier(id: SwiftData.PersistentIdentifier.ID(backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(0x9dde110179619224 x-coredata://D4C9A4D3-8E7F-49B2-A07B-FD91A8906552/Child/p8)), backing: SwiftData.PersistentIdentifier.PersistentIdentifierBacking.managedObjectID(0x9dde110179619224 x-coredata://D4C9A4D3-8E7F-49B2-A07B-FD91A8906552/Child/p8)) without a context SwiftData._FullFutureBackingData<SwiftData_Bootcamp.Child>
触发崩溃的场景是:我在DetailView中删除一个Adult实例,然后调用dismiss()返回列表页的时候,App直接崩溃了。
我的数据模型结构
我定义了两个简单的模型Adult和Child,均继承自Person基础类,它们的关联关系如下:
// Adult @Model class Adult: Person { var id: UUID = UUID() var name: String var age: Int @Relationship(deleteRule: .cascade) var children: [Child] = [] init(name: String, age: Int) { self.name = name self.age = age } } // Child @Model class Child: Person { var id: UUID = UUID() var name: String var age: Int init(name: String, age: Int) { self.name = name self.age = age } }
预期行为
我设置了@Relationship(deleteRule: .cascade),所以预期删除一个Adult实例时,所有关联的Child实例会被自动级联删除,不需要手动处理。
崩溃触发的具体场景
崩溃发生在DetailView中执行删除操作后调用dismiss()的瞬间,核心代码逻辑如下:
struct DetailView: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss let adult: Adult private func delete() { do { modelContext.delete(adult) try modelContext.save() } catch { print(error.localizedDescription) } dismiss() } }
完整UI代码(供参考)
ContentView
struct ContentView: View { @Query(animation: .default) private var adults: [Adult] @Query(animation: .default) private var children: [Child] @State private var showForm: Bool = false var body: some View { NavigationStack { List { if adults.isEmpty { Text("无数据") } else { ForEach(adults) { adult in NavigationLink(value: adult) { row(adult) } } } } .navigationTitle("Persons") .toolbar { ToolbarItem(content: createButton) } .navigationDestination( isPresented: $showForm, destination: { FormView() } ) .navigationDestination( for: Adult.self, destination: { adult in DetailView(adult: adult) } ) } } } #Preview { ContentView() .modelContainer(for: Adult.self, inMemory: true) .modelContainer(for: Child.self, inMemory: true) } extension ContentView { private func row(_ data: Adult) -> some View { HStack { Text(data.name) Spacer() Text("孩子: \(data.children.count)") } } private func createButton() -> some View { Button("创建", systemImage: "plus") { showForm.toggle() } } }
DetailView 完整代码
struct DetailView: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss let adult: Adult var body: some View { List { Section("基本信息") { LabeledContent("姓名", value: adult.name) LabeledContent("岁数", value: adult.age, format: .number) } Section("娃") { if adult.children.isEmpty { Text("没娃") } else { ForEach(adult.children) { child in LabeledContent(child.name) { Text("\(child.age)岁") } } } } Button("删除", role: .destructive, action: delete) } } } #Preview { DetailView(adult: .init(name: "noah", age: 5)) } extension DetailView { private func delete() { do { modelContext.delete(adult) try modelContext.save() } catch { print(error.localizedDescription) } dismiss() } }
FormView 完整代码
struct FormView: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss @State private var name: String = "" @State private var age: Int = 1 var body: some View { Form { TextField("姓名", text: $name) Stepper("岁数", value: $age) Section { Button("创建", action: create) .disabled(name.isEmpty) } } } } #Preview { FormView() } extension FormView { private func create() { let adult = Adult(name: name, age: age) let childCount = Int.random(in: 1...5) for _ in 0..<childCount { let child = Child( name: names.randomElement() ?? "二狗", age: Int.random(in: 0...16) ) adult.children.append(child) } modelContext.insert(adult) do { try modelContext.save() } catch { print(error.localizedDescription) } dismiss() } }
我的疑问
- 为什么使用
.cascade删除规则会触发这个崩溃?是不是我误解了SwiftData中@Relationship(deleteRule:)的工作方式? - 我该如何正确实现“删除Adult时自动删除所有关联Child”的功能,同时避免这个崩溃?
我已经反复看了苹果官方的@Relationship API文档,但可能漏掉了某些细节,希望各位能帮忙指点一下!
内容来源于stack exchange
相关产品推荐
相关产品推荐

