Swift 4 iOS:Bundle中本地JSON文件无法写入的问题求助
为什么你无法写入Bundle里的JSON文件?
嘿,这个问题我碰到过好多次啦!你之所以写操作失败,核心原因是App的主Bundle是只读的——苹果为了保障App的完整性和安全性,不允许直接修改Bundle内的任何资源文件,哪怕你拿到了它的URL也没用。
那该怎么解决呢?我们需要把JSON文件复制到App的可读写沙盒目录里(比如Documents目录),之后所有的读写操作都针对这个复制后的文件来做。
完整解决方案步骤
1. 获取可读写的文件URL
先定义一个方法,用来获取Documents目录下的目标文件路径:
func getWritableCategoriesFileURL() -> URL? { // 获取Documents目录的URL guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return nil } // 拼接目标文件的完整URL return documentsDir.appendingPathComponent("categories.json") }
2. 初始化:把Bundle文件复制到Documents(仅第一次执行)
在App启动或者首次操作文件时,检查Documents里是否已有该文件,如果没有就从Bundle复制过去:
func copyBundleFileToDocumentsIfNeeded() { guard let bundleFileURL = Bundle.main.url(forResource: "categories", withExtension: "json"), let writableFileURL = getWritableCategoriesFileURL() else { return } // 检查Documents目录是否已存在目标文件 if !FileManager.default.fileExists(atPath: writableFileURL.path) { do { // 执行复制操作 try FileManager.default.copyItem(at: bundleFileURL, to: writableFileURL) print("文件已成功复制到Documents目录") } catch { print("复制文件失败:\(error.localizedDescription)") } } }
3. 修改读取逻辑:从Documents目录读取
把原来读取Bundle文件的代码,改成读取Documents里的可写文件:
func readCategories() -> Any? { guard let writableFileURL = getWritableCategoriesFileURL(), let data = try? Data(contentsOf: writableFileURL) else { return nil } do { let json = try JSONSerialization.jsonObject(with: data, options: []) return json } catch { print("读取JSON失败:\(error.localizedDescription)") return nil } }
4. 修改写入逻辑:写入到Documents目录
现在你的写入操作就能正常执行了,替换掉原来指向Bundle的URL:
func writeCategories(_ categories: [YourCategoryModel]) { guard let writableFileURL = getWritableCategoriesFileURL() else { return } let dict = ["data": categories.compactMap { $0.dictionary }] do { // 加.prettyPrinted可以让生成的JSON格式更美观,方便调试 let jsonData = try JSONSerialization.data(withJSONObject: dict, options: [.prettyPrinted]) try jsonData.write(to: writableFileURL) print("JSON写入成功!") } catch { print("写入JSON失败:\(error.localizedDescription)") } }
额外提示
- 记得在App启动时调用
copyBundleFileToDocumentsIfNeeded(),比如在AppDelegate的didFinishLaunchingWithOptions里,或者SceneDelegate的scene(_:willConnectTo:options:)方法中。 - 如果需要查看
Documents目录里的文件,可以通过Xcode的Window > Devices and Simulators,选中你的App,点击Download Container导出沙盒文件进行查看。
内容的提问来源于stack exchange,提问作者Tabula Rasa
相关产品推荐
相关产品推荐

