iPad端SplitNavigationView中SwiftData删除未触发视图更新
问题描述
- 在iPad设备的
NavigationSplitView侧边栏中,点击工具栏按钮弹出的sheet支持加载/删除SwiftData对象,加载功能正常,但删除所有对象的操作无效果,视图也不触发更新 - 已通过环境注入
ModelContext,尝试直接向sheet注入ModelContext结果一致,甚至重启应用后数据有时并未被删除
问题根源
你使用的try context.delete(model: Monkey.self)是直接操作持久化存储的方法,它不会同步清理当前ModelContext中已经加载的对象缓存。而@Query是基于上下文的缓存数据进行更新的,所以即使存储里的数据被删了,视图依然会显示缓存中的旧数据。如果上下文存在未提交的变更,这个操作甚至不会正确同步到存储。
修复方案
可以采用两种可靠的方式实现全量删除并触发视图更新:
方案一:获取所有对象后逐个删除
这种方式会通过上下文处理删除,自动触发@Query的视图更新:
Button("Delete") { let fetchDescriptor = FetchDescriptor<Monkey>() if let allMonkeys = try? context.fetch(fetchDescriptor) { allMonkeys.forEach { context.delete($0) } print("Deleted all the Monkeys") } }
方案二:清理存储后强制刷新上下文
如果坚持使用批量删除存储的方式,需要手动刷新上下文来同步缓存:
Button("Delete") { do { try context.delete(model: Monkey.self) // 强制刷新上下文,同步存储状态到缓存 try context.fetch(FetchDescriptor<Monkey>()) print("Deleted all the Monkeys") } catch { print("Failed to delete all Monkeys: \(error.localizedDescription)") } }
修改后的完整SettingsSheet代码
struct SettingsSheet: View { @Environment(\.modelContext) var context var body: some View { NavigationStack { HStack { Button("Load") { for _ in 0...9 { let monkey = Monkey(name: String(Int.random(in: 0...999))) context.insert(monkey) } } // 使用方案一的实现 Button("Delete") { let fetchDescriptor = FetchDescriptor<Monkey>() if let allMonkeys = try? context.fetch(fetchDescriptor) { allMonkeys.forEach { context.delete($0) } print("Deleted all the Monkeys") } } } .navigationTitle("Monkey Settings") } } }
内容的提问来源于stack exchange,提问作者Magnas
相关产品推荐
相关产品推荐

