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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 01:01:10