SwiftData NavigationSplitView中onDelete无法可靠删除列表项求助
问题根源分析
- 错误的删除逻辑:原代码中
onDelete仅当要删除的项等于当前选中项时才执行删除,这意味着大多数滑动删除操作实际未生效——删除的项看似消失只是视图临时刷新,后续切换选中项时,未被真正删除的项会重新出现。 - 强引用残留:若已删除的项仍被
selectedThing持有强引用,SwiftData无法正确回收该对象,在视图状态更新时会重新将其纳入查询结果。 - 上下文未及时同步:插入或删除对象后未立即保存上下文,导致数据状态与视图显示不同步,加剧了内容重现的问题。
修复后的代码
修正ContentView中的核心逻辑
struct ContentView: View { @Environment(\.modelContext) private var context @Query(sort: \Thing.name, order: .forward) var things: [Thing] @State private var selectedThing: Thing? var body: some View { NavigationSplitView { VStack { Text("Some Things") List(selection: $selectedThing) { ForEach(things, id: \.self) { thing in HStack { Text(thing.name) Text(thing.areYouSure.description) } } .onDelete{ indexSet in indexSet.forEach { index in let targetThing = things[index] // 若要删除的是当前选中项,清空选中状态解除强引用 if targetThing == selectedThing { selectedThing = nil } context.delete(targetThing) } // 立即保存上下文确保状态同步 do { try context.save() } catch { print(error) } } } } .toolbar { ToolbarItem(placement: .topBarTrailing) { Button { AddFourThings() } label: { Image(systemName: "plus") } } } } detail: { ZStack { if let selectedThing { DetailView(thing: selectedThing) } else { Text("Choose a Thing") } } } } private func AddFourThings() { let thing1 = Thing(name: "Thing One", areYouSure: true) let thing2 = Thing(name: "Thing Two", areYouSure: false) let thing3 = Thing(name: "Thing Three", areYouSure: true) let thing4 = Thing(name: "Thing Four", areYouSure: false) context.insert(thing1) context.insert(thing2) context.insert(thing3) context.insert(thing4) // 插入后保存上下文,避免数据同步延迟 do { try context.save() } catch { print(error) } } }
其余代码保持不变
DetailView和Thing模型无需修改,确保Thing类正确标记@Model即可。
额外注意事项
- 由于当前使用的是Xcode 15 Beta版本,若修复后仍存在问题,可能是SwiftData的Beta版bug,可尝试更新至最新Beta版本,或通过
context.refreshAll()在合适时机强制刷新上下文状态。 - 避免在视图层长期持有SwiftData模型对象的强引用,尽量通过
@Query或上下文查询获取最新状态。
内容的提问来源于stack exchange,提问作者JohnSF
相关产品推荐
相关产品推荐

