iOS Swift中JSON读取到数组后 数组变更时回写JSON方案
核心问题说明
你的代码存在3个直接导致写入失效的逻辑错误:
- 读写路径不匹配:读取初始数据时读的是Bundle下的
recipeData.json,写入时却写到Documents目录下命名为test.json,且Bundle是应用只读目录,本身不允许写入运行时数据,原有加载逻辑也永远不会读取你写入到Documents目录的内容 - 写入逻辑错误:循环遍历单条菜谱逐个调用文件写入方法,每次写入都会覆盖上一次的文件内容,最终文件只会残留最后一条菜谱的单对象JSON,根本不是合法的数组结构
- 初始化逻辑缺失:首次启动时没有把Bundle内的初始JSON拷贝到可写目录,Documents目录下不存在目标文件时,写入逻辑虽然执行但没有和加载逻辑打通,后续启动也读不到写入的内容
可直接运行的修正方案
1. 统一读写路径,修正加载逻辑
所有持久化数据统一存到沙盒Documents目录,加载时优先读用户持久化的自定义数据,不存在时再加载Bundle内置初始数据并拷贝到可写目录:
import UIKit import SwiftUI // 全局统一的持久化文件路径 let persistentRecipePath: URL = { guard let documentDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { fatalError("无法访问沙盒Documents目录") } return documentDir.appendingPathComponent("recipeData.json") }() // 初始化加载菜谱数据 var recipeData: [Recipe] = { // 优先加载已经持久化的用户数据 if FileManager.default.fileExists(atPath: persistentRecipePath.path), let localData = try? Data(contentsOf: persistentRecipePath), let decodedRecipes = try? JSONDecoder().decode([Recipe].self, from: localData) { return decodedRecipes } // 无本地持久化数据时,加载Bundle内置初始数据 guard let bundleInitialPath = Bundle.main.url(forResource: "recipeData.json", withExtension: nil) else { fatalError("未找到Bundle内置的初始recipeData.json文件,请检查文件是否加入编译目标") } do { let initialData = try Data(contentsOf: bundleInitialPath) // 将初始数据拷贝到可写目录,后续读写都走这个路径 try initialData.write(to: persistentRecipePath, options: .atomic) return try JSONDecoder().decode([Recipe].self, from: initialData) } catch { fatalError("初始菜谱数据加载失败: \(error.localizedDescription)") } }()
2. 修正写入方法
不要循环单条写入,直接对整个菜谱数组做编码后一次性写入文件,保证JSON结构合法:
func saveRecipeData() { do { let encodedData = try JSONEncoder().encode(recipeData) try encodedData.write(to: persistentRecipePath, options: .atomic) } catch { print("菜谱数据持久化失败: \(error.localizedDescription)") } }
3. 实现变更自动触发写入
如果使用SwiftUI开发,建议将菜谱数据封装到ObservableObject中,通过属性监听器实现数据变更自动持久化:
class RecipeStore: ObservableObject { @Published var recipes: [Recipe] = recipeData { didSet { recipeData = recipes saveRecipeData() } } }
后续所有对菜谱数组的增删改操作都通过RecipeStore实例的recipes属性操作,变更后会自动触发持久化,不需要手动调用写入方法。
内容的提问来源于stack exchange,提问作者voodoomamajuju
相关产品推荐
相关产品推荐

