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

将Codable类型Plant数组编码为JSON后,如何持久化存储?

解决Codable对象数组的持久化问题

嘿,我明白你现在的困惑——用JSONEncoder编码了[Plant]数组后,不知道怎么把数据持久化下来,保证应用重启后还能读到,对吧?之前用NSCoder的归档方式有一套固定流程,换成Codable其实思路类似,只是更简洁高效。我给你两种常用的实现方案,按需选择就好:

方式一:用UserDefaults存储(适合小量数据)

如果你的Plant数组数据量不大,UserDefaults是最方便的轻量级存储方案。我们可以把这个逻辑整合到你的单例类里,补全后的代码如下:

import Foundation

public class PlantManager {
    // 单例实例,全局唯一
    static let shared = PlantManager()
    
    // 存储所有Plant的数组
    var plants: [Plant] = []
    
    // 私有初始化,避免外部创建多个实例
    private init() {
        // 应用启动时自动加载已保存的数据
        loadSavedPlants()
    }
    
    // 保存当前plants数组到UserDefaults
    func savePlants() {
        do {
            // 把Plant数组编码为Data
            let encodedData = try JSONEncoder().encode(plants)
            // 用唯一的key存入UserDefaults
            UserDefaults.standard.set(encodedData, forKey: "SavedPlantList")
        } catch {
            print("保存植物数据失败:\(error.localizedDescription)")
        }
    }
    
    // 从UserDefaults加载已保存的Plant数组
    private func loadSavedPlants() {
        guard let savedData = UserDefaults.standard.data(forKey: "SavedPlantList") else {
            return // 没有已保存数据,直接返回空数组
        }
        do {
            plants = try JSONDecoder().decode([Plant].self, from: savedData)
        } catch {
            print("加载植物数据失败:\(error.localizedDescription)")
        }
    }
}

使用起来很简单:当你修改了plants数组(比如添加、删除植物)后,调用PlantManager.shared.savePlants()就能把数据持久化。下次启动应用时,单例初始化会自动调用loadSavedPlants(),把之前保存的数据读回来。

方式二:用Documents目录存储(适合大量数据)

如果你的Plant数组数据量比较大,或者需要更稳定的存储,建议把数据写到应用的Documents目录下的本地文件里。修改后的单例类代码如下:

import Foundation

public class PlantManager {
    static let shared = PlantManager()
    var plants: [Plant] = []
    
    // 获取存储文件的路径:Documents目录下的plants.json
    private var plantFileURL: URL {
        let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        return documentsDir.appendingPathComponent("plants.json")
    }
    
    private init() {
        loadSavedPlants()
    }
    
    func savePlants() {
        do {
            let encodedData = try JSONEncoder().encode(plants)
            // 把Data写入指定路径的文件
            try encodedData.write(to: plantFileURL)
        } catch {
            print("保存植物数据失败:\(error.localizedDescription)")
        }
    }
    
    private func loadSavedPlants() {
        // 先判断文件是否存在
        guard FileManager.default.fileExists(atPath: plantFileURL.path) else {
            return
        }
        do {
            let savedData = try Data(contentsOf: plantFileURL)
            plants = try JSONDecoder().decode([Plant].self, from: savedData)
        } catch {
            print("加载植物数据失败:\(error.localizedDescription)")
        }
    }
}

这种方式的使用逻辑和UserDefaults版本完全一致,只是数据存储在本地文件中,比UserDefaults更适合大量数据的场景,也更稳定。

和NSCoder方式的对比

之前用NSCoder时,需要让Plant实现NSCoding协议,手动写encode(with:)和required convenience init?(coder:)的模板代码。而Codable是Swift更现代的序列化方案,只要你的Plant的所有属性都是基础类型(String、Int、Date等)或者也遵循Codable,那Plant只需要声明遵循Codable就行,不需要额外写序列化代码,大大减少了模板工作量。

另外,如果你的Plant里有Date这类特殊类型,还可以给JSONEncoder/JSONDecoder设置自定义编码策略,比如:

let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .iso8601 // 用ISO8601格式编码日期

内容的提问来源于stack exchange,提问作者Gabe Spound

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:00:52