Swift如何修改本地JSON加载的Movie数据并实现多页面同步更新展示
问题根本原因
- 你在每个用到
moviedata的页面都单独执行了@ObservedObject var movieData=moviedata(),相当于每个页面都持有一个独立的moviedata实例,所有实例都会从Bundle加载原始JSON数据,你在A页面修改的是A实例的内存数据,B页面读取的是B实例的原始数据,自然不会同步。 - 你当前的修改仅存在于内存中,Bundle内的原始JSON是只读不可修改的,App重启后所有修改都会重置。
修复方案
1. 全局唯一数据源配置
给moviedata类添加单例配置,禁止外部随意创建新实例,保证全App读写同一份数据:
class moviedata: ObservableObject { // 全局唯一共享实例 static let shared = moviedata() @Published var myMovieData:[Movie] = [] // 私有初始化方法,防止外部新建实例 private init() { myMovieData = Bundle.main.decode(filename:"movieData1.json") } }
在App主入口将共享实例注入到视图树中,所有子页面都可以直接读取:
// 你的App入口文件,比如XXApp.swift @main struct MovieApp: App { // 持有全局数据实例用@StateObject,避免实例被意外销毁 @StateObject private var movieData = moviedata.shared var body: some Scene { WindowGroup { // 替换成你的根视图 ContentView() .environmentObject(movieData) } } }
2. 所有页面统一读取全局数据
把myPage里单独初始化moviedata的代码替换为读取环境对象,其他用到电影数据的页面也做相同修改:
// 删掉原来的@ObservedObject var movieData=moviedata(),换成下面这行 @EnvironmentObject var movieData: moviedata
修改完成后所有页面读写的都是同一份数据,修改后会自动同步到所有引用页面。
3. 可选:实现修改持久化
如果需要App重启后仍保留修改内容,需要把修改后的数据写入沙盒目录,下次启动优先读取沙盒数据,没有再加载Bundle原始文件。
给moviedata添加读写沙盒的扩展方法:
extension moviedata { // 加载数据:优先读沙盒,没有再读Bundle原始数据 func loadData() { let sandboxPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("movieData1.json") guard let data = try? Data(contentsOf: sandboxPath), let decodedData = try? JSONDecoder().decode([Movie].self, from: data) else { // 沙盒无数据,加载Bundle原始文件 myMovieData = Bundle.main.decode(filename:"movieData1.json") return } myMovieData = decodedData } // 将修改后的数据保存到沙盒 func saveToSandbox() { let sandboxPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("movieData1.json") do { let encodedData = try JSONEncoder().encode(myMovieData) try encodedData.write(to: sandboxPath) } catch { print("数据保存失败: \(error.localizedDescription)") } } }
修改moviedata的初始化方法调用loadData:
private init() { loadData() }
每次修改数据后调用保存方法即可持久化:
Button("comfirm"){ movieData.myMovieData[index].DOUBAN_VOTES=String(temp) movieData.saveToSandbox() }
内容的提问来源于stack exchange,提问作者Hannah
相关产品推荐
相关产品推荐

