SwiftUI中如何批量加载与保存多个@Published编码属性?
实现方案
完全可以实现批量加载/保存的需求,推荐用结构体替代元组(元组的扩展性和维护性较差),以下是具体实现方案:
1. 定义统一的数据存储结构体
先创建一个符合Codable协议的结构体,把所有需要持久化的数组类型整合进去,后续新增属性直接在结构体中添加即可:
struct AppData: Codable { var events: [Event] var contacts: [Contact] var services: [Service] // 后续新增属性直接追加,比如: // var tasks: [Task] = [] }
注意:
Event、Contact、Service这三个类型也必须符合Codable协议,否则无法完成JSON序列化/反序列化。
2. 重构ObservableObject存储类
将原来的三个独立@Published属性替换为一个包含AppData的@Published属性,统一管理所有数据:
class DataStore: ObservableObject { @Published var appData: AppData = AppData(events: [], contacts: [], services: []) // 获取本地存储文件路径 private static func fileURL() throws -> URL { try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) .appendingPathComponent("app_data.data") } // 批量加载所有数据 static func load(completion: @escaping (Result<AppData, Error>) -> Void) { DispatchQueue.global(qos: .background).async { do { let fileURL = try fileURL() // 文件不存在时返回空的默认数据 guard let data = try? Data(contentsOf: fileURL) else { DispatchQueue.main.async { completion(.success(AppData(events: [], contacts: [], services: []))) } return } let decodedData = try JSONDecoder().decode(AppData.self, from: data) DispatchQueue.main.async { completion(.success(decodedData)) } } catch { DispatchQueue.main.async { completion(.failure(error)) } } } } // 批量保存所有数据 static func save(_ data: AppData, completion: @escaping (Result<Void, Error>) -> Void) { DispatchQueue.global(qos: .background).async { do { let fileURL = try fileURL() let encodedData = try JSONEncoder().encode(data) try encodedData.write(to: fileURL) DispatchQueue.main.async { completion(.success(())) } } catch { DispatchQueue.main.async { completion(.failure(error)) } } } } }
3. 视图中使用方式
直接通过appData的子属性访问对应数组,加载和保存操作统一调用批量方法:
struct ContentView: View { @StateObject private var store = DataStore() var body: some View { List { Section("Events") { ForEach(store.appData.events) { event in Text(event.title) } } Section("Contacts") { ForEach(store.appData.contacts) { contact in Text(contact.name) } } Section("Services") { ForEach(store.appData.services) { service in Text(service.name) } } } .onAppear { // 页面加载时读取本地数据 DataStore.load { result in switch result { case .success(let data): store.appData = data case .failure(let error): print("加载失败:\(error.localizedDescription)") } } } .onDisappear { // 页面消失时保存所有数据 DataStore.save(store.appData) { result in if case .failure(let error) = result { print("保存失败:\(error.localizedDescription)") } } } } }
后续扩展
如果以后需要新增持久化数组,只需要两步:
- 在
AppData结构体中添加新属性(比如var tasks: [Task] = [],确保Task符合Codable) - 在视图中直接通过
store.appData.tasks访问即可,无需修改load和save方法
内容的提问来源于stack exchange,提问作者Roman R
相关产品推荐
相关产品推荐

