将Codable类型Plant数组编码为JSON后,如何持久化存储?
嘿,我明白你现在的困惑——用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

