Swift本地化JSON编解码:迁移至DocumentDirectory实现数据持久化
把JSON迁移到DocumentDirectory实现数据持久化的分步指南
嘿,你已经搞定了最麻烦的部分——加载JSON、折叠单元格和滑块交互,剩下的把数据移到可读写的DocumentDirectory并实现持久化其实很简单,我来一步步给你拆解:
1. 先搞懂为什么要迁移到DocumentDirectory
Bundle里的文件是只读的,你没法修改后写回去,所以必须把初始JSON复制到App的DocumentDirectory(这个目录是App专属的可读写空间,只有用户卸载App时才会被删除)。
2. 获取DocumentDirectory的文件路径
先写个工具函数帮你快速拿到目标文件的URL:
func getDocumentFilePath(for fileName: String) -> URL? { guard let docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { print("无法获取DocumentDirectory路径") return nil } return docsDir.appendingPathComponent(fileName) }
3. 首次启动时复制初始JSON到DocumentDirectory
我们要确保只在第一次启动时复制,避免覆盖用户已经修改的数据:
func copyInitialJSONToDocuments() { // 从Bundle拿到初始JSON的路径 guard let bundleJSONPath = Bundle.main.path(forResource: "financetoday", ofType: "json"), let destURL = getDocumentFilePath(for: "financetoday.json") else { return } // 检查目标路径是否已有文件,没有才复制 if !FileManager.default.fileExists(atPath: destURL.path) { do { try FileManager.default.copyItem(atPath: bundleJSONPath, toPath: destURL.path) print("初始JSON已成功复制到DocumentDirectory") } catch { print("复制JSON失败:\(error.localizedDescription)") } } }
记得在App启动时调用这个方法,比如在SceneDelegate的sceneDidBecomeActive里,或者你的ViewModel初始化的时候。
4. 修改数据加载逻辑:从DocumentDirectory读取
把原来从Bundle加载的代码替换成从DocumentDirectory读取:
// 假设你的数据模型是FinancialItem,并且遵循Codable协议 func loadFinancialData() -> [FinancialItem]? { guard let fileURL = getDocumentFilePath(for: "financetoday.json"), let data = try? Data(contentsOf: fileURL) else { print("无法读取DocumentDirectory中的JSON文件") return nil } do { let decoder = JSONDecoder() return try decoder.decode([FinancialItem].self, from: data) } catch { print("解析JSON失败:\(error.localizedDescription)") return nil } }
5. 实现数据保存:修改后写回DocumentDirectory
当滑块改变数值时,更新内存中的模型,然后把整个模型数组转成JSON写回文件:
func saveFinancialData(_ items: [FinancialItem]) { guard let fileURL = getDocumentFilePath(for: "financetoday.json") else { return } do { let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted // 可选,让生成的JSON更易读 let jsonData = try encoder.encode(items) try jsonData.write(to: fileURL) print("数据已成功保存") } catch { print("保存数据失败:\(error.localizedDescription)") } }
6. 绑定滑块的修改事件
在你的滑块valueChanged方法里,更新模型并触发保存:
@IBAction func sliderValueChanged(_ sender: UISlider) { // 拿到当前滑块所在单元格的索引 guard let cell = sender.superview?.superview as? YourCustomCell, let indexPath = tableView.indexPath(for: cell), var currentItems = self.financialItems else { return } // 更新内存中的模型数据 let newValue = sender.value currentItems[indexPath.row].targetValue = newValue // 替换成你模型里对应的数值属性 // 更新数据源并保存 self.financialItems = currentItems saveFinancialData(currentItems) // 可选:刷新单元格显示 tableView.reloadRows(at: [indexPath], with: .automatic) }
一些额外提示
- 一定要用
do-catch包裹文件操作和JSON编解码,避免崩溃,同时方便排查错误 - 确保你的数据模型严格遵循
Codable协议,否则JSON编解码会失败 - 如果数据量比较大,建议把保存操作放到后台队列执行,避免阻塞主线程影响UI流畅度
这样一来,用户修改的数值就会持久化到DocumentDirectory里,下次启动App时就能加载最新的数据啦!
内容的提问来源于stack exchange,提问作者Brian Rem
相关产品推荐
相关产品推荐

