iOS主应用Bundle内JSON文件无法更新,如何实现正确读写?
无法更新Xcode Bundle内JSON文件的解决方案
你碰到的问题根源很明确:iOS App的主Bundle是只读的——系统为了防止App被篡改,完全禁止对安装包内的文件进行写入操作。你直接尝试往Bundle.main.url返回的路径写数据,本质上是不被允许的,要么会直接报错,要么系统会把文件写到其他地方(比如你看到的Documents目录里的新文件),但这绝不是你想要的效果。
正确的做法是:把Bundle里的初始JSON文件复制一份到App的Documents目录(这个目录是可读写的),之后所有的读取和更新操作都针对Documents里的这份文件。下面是具体的实现步骤和代码:
1. 封装获取目标文件路径的方法
先写一个工具方法,负责检查Documents目录里有没有我们需要的data.json,如果没有就从Bundle里复制过去:
func getAppDataFileURL() -> URL { // 获取Documents目录的路径 let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! let targetFileURL = documentsDirectory.appendingPathComponent("data.json") // 如果Documents里没有该文件,从Bundle复制初始化数据 guard FileManager.default.fileExists(atPath: targetFileURL.path) else { guard let bundleSourceURL = Bundle.main.url(forResource: "data", withExtension: "json") else { fatalError("找不到Bundle里的data.json文件,请检查文件名是否正确") } do { try FileManager.default.copyItem(at: bundleSourceURL, to: targetFileURL) } catch { fatalError("复制初始数据文件失败:\(error.localizedDescription)") } return targetFileURL } return targetFileURL }
2. 修改你的更新代码
现在把原来直接操作Bundle路径的代码,改成操作Documents目录里的文件:
// 获取可读写的目标文件URL let targetURL = getAppDataFileURL() // 将contact转换为JSON数据(这里推荐用系统的JSONSerialization,比第三方库的description转字符串更可靠) do { // 如果用的是SwiftyJSON,可以换成 let jsonData = JSON(contact).rawData() let jsonData = try JSONSerialization.data(withJSONObject: contact, options: .prettyPrinted) // 写入文件,用.atomic选项保证写入过程中文件不会损坏 try jsonData.write(to: targetURL, options: .atomic) print("JSON文件更新成功") } catch { print("更新JSON文件出错:\(error.localizedDescription)") }
3. 读取文件时也要用这个路径
以后你需要读取JSON数据时,同样调用getAppDataFileURL()获取路径,而不是再从Bundle里读取,这样拿到的就是最新修改后的内容。
额外注意事项
- 为什么不用
description转字符串再转Data?:这种方式容易引入格式问题(比如多余的转义字符、换行符),直接用JSON库的rawData()或者系统的JSONSerialization生成Data才是正确的做法。 .atomic选项的作用:写入时会先创建一个临时文件,写入完成后再替换原文件,避免因为中途崩溃导致文件损坏。
内容的提问来源于stack exchange,提问作者kiki
相关产品推荐
相关产品推荐

