SwiftUI中UserDefaults删除项后重启模拟器恢复问题求解
问题解决:删除ExpenseItem后UserDefaults恢复已删除项的问题
问题根源
UserDefaults的set(_:forKey:)并非实时同步到磁盘,它会在系统调度的合适时机批量写入磁盘。当你删除项后立刻终止模拟器,内存中更新的数据还没来得及完成持久化操作,下次启动时就会读取到之前未更新的缓存内容,导致已删除项“恢复”。
解决方案
方案1:强制UserDefaults同步写入
在didSet中调用synchronize()方法,强制将内存中的修改立即写入磁盘。虽然苹果文档不推荐在常规场景下使用该方法,但在需要确保即时持久化的场景下能解决问题:
didSet { let encoder = JSONEncoder() if let encoded = try? encoder.encode(items) { UserDefaults.standard.set(encoded, forKey: "itemsData") UserDefaults.standard.synchronize() // 强制同步到磁盘 } }
方案2:改用沙盒文件直接存储(更可靠)
相比依赖UserDefaults的异步机制,直接将数据写入沙盒中的JSON文件可以完全控制写入时机,确保修改即时持久化:
class Expenses: ObservableObject { @Published var items = [ExpenseItem]() { didSet { saveItems() } } // 获取沙盒中保存文件的路径 private let savePath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("items.json") init() { loadItems() } private func saveItems() { let encoder = JSONEncoder() do { let encoded = try encoder.encode(items) // 原子写入:先写临时文件,成功后替换目标文件,避免写入中断导致文件损坏 try encoded.write(to: savePath, options: .atomicWrite) } catch { print("保存失败:\(error)") } } private func loadItems() { do { let data = try Data(contentsOf: savePath) let decoded = try JSONDecoder().decode([ExpenseItem].self, from: data) items = decoded } catch { items = [] } } }
方案3:完善错误处理(可选)
原代码中使用try?会忽略编码错误,若编码失败UserDefaults不会更新。可以添加错误处理逻辑,确保只有编码成功时才更新存储:
didSet { let encoder = JSONEncoder() do { let encoded = try encoder.encode(items) UserDefaults.standard.set(encoded, forKey: "itemsData") UserDefaults.standard.synchronize() } catch { print("编码失败:\(error)") } }
内容的提问来源于stack exchange,提问作者Ali Almahoozi
相关产品推荐
相关产品推荐

