You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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)")
                }
            }
        }
    }
}

后续扩展

如果以后需要新增持久化数组,只需要两步:

  1. 在AppData结构体中添加新属性(比如var tasks: [Task] = [],确保Task符合Codable)
  2. 在视图中直接通过store.appData.tasks访问即可,无需修改load和save方法

内容的提问来源于stack exchange,提问作者Roman R

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 11:58:28