如何在App关闭后保存自定义结构体数据?@AppStorage使用遇阻
存储自定义结构体数组的最佳方案
为什么@AppStorage无法直接使用
@AppStorage仅支持符合RawRepresentable的基础类型(如String、Int、Bool等),你的[ToDoTasks]是自定义结构体数组,无法直接被@AppStorage处理,这就是你之前尝试失败的原因。
推荐方案:UserDefaults + Codable + ObservableObject
因为你的ToDoTasks已经实现了Codable协议,我们可以将数组编码为Data后存入UserDefaults,读取时再解码回数组。结合ObservableObject可以更优雅地管理数据的读写逻辑:
步骤1:创建ViewModel管理数据
class ToDoViewModel: ObservableObject { @Published var items: [ToDoTasks] = [] private let storageKey = "SavedToDoTasks" init() { loadSavedTasks() } // 从UserDefaults读取数据 private func loadSavedTasks() { guard let savedData = UserDefaults.standard.data(forKey: storageKey) else { // 无保存数据时使用默认值 items = [ToDoTasks(task: "Test", date: Date())] return } do { items = try JSONDecoder().decode([ToDoTasks].self, from: savedData) } catch { print("数据解码失败:\(error.localizedDescription)") items = [ToDoTasks(task: "Test", date: Date())] } } // 将数据保存到UserDefaults func saveTasks() { do { let encodedData = try JSONEncoder().encode(items) UserDefaults.standard.set(encodedData, forKey: storageKey) } catch { print("数据编码失败:\(error.localizedDescription)") } } }
步骤2:在View中使用ViewModel
struct ContentView: View { // 使用@StateObject初始化ViewModel,确保生命周期与View一致 @StateObject private var viewModel = ToDoViewModel() var body: some View { VStack { // 示例:展示任务列表 List(viewModel.items) { task in VStack(alignment: .leading) { Text(task.task) Text(task.date.formatted()) .font(.caption) .foregroundColor(.gray) } } // 示例:添加新任务 Button("添加任务") { viewModel.items.append(ToDoTasks(task: "新任务", date: Date())) viewModel.saveTasks() } } // 可选:监听items变化自动保存,无需手动调用saveTasks .onChange(of: viewModel.items) { _ in viewModel.saveTasks() } } }
替代方案:Core Data(适合复杂场景)
如果你的待办任务数量较多,或者需要支持复杂查询、关联数据等操作,Core Data会是更合适的选择。它提供了更强大的数据持久化能力,但学习成本比UserDefaults高一些。
内容的提问来源于stack exchange,提问作者Halas Wolff
相关产品推荐
相关产品推荐

