构建 iOS 应用程序 - 在真实设备上测试时不允许使用 Swift 保存 JSON 文件,但在模拟器上它可以工作

问题描述 投票:0回答:1

我正在尝试制作一个 iOS 应用程序,我必须保存一个 JSON 文件,但我收到此错误:

Landmarks/ModelData.swift:45:致命错误:无法写入 /private/var/containers/Bundle/Application/.../Landmarks.app/landmarkData.json: 错误域=NSCocoaErrorDomain代码=513“您无权将文件“landmarkData.json”保存在“Landmarks”文件夹中。”

但是,这只发生在我的 iPhone 11 上测试应用程序时,在模拟器上运行应用程序时,它按预期工作。

这是我正在使用的保存功能:

func save(_ landmarks: [Landmark]) {
    let encoder = JSONEncoder()
    
    do {
        let data = try encoder.encode(landmarks)
        let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let fileURL = documentsDirectory.appendingPathComponent("landmarkData.json")
        guard let file = Bundle.main.url(forResource: "landmarkData.json", withExtension: nil)
        else {
            fatalError("Couldn't find landmarkData.json in main bundle.")
        }
        
        do {
            try data.write(to: file)
        } catch {
            fatalError("Couldn't write to \(file.path):\n\(error)")
        }
    } catch {
        fatalError("Couldn't encode landmarks as JSON:\n\(error)")
    }
}

我想我必须将文件保存在另一个文件夹中,例如文档文件夹,但我不确定该怎么做。

我试过这个:

import Foundation

@Observable
class ModelData {
    init() {
        copyFileFromBundleToDocumentsFolder(sourceFile: "landmarkData.json")
        landmarks = load("landmarkData.json")
    }
    
    var landmarks: [Landmark] = []
}

func load<T: Decodable>(_ filename: String) -> T {
    let data: Data
    
    let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    let fileURL = documentsURL.appendingPathComponent(filename)
    
    do {
        data = try Data(contentsOf: fileURL)
    } catch {
        fatalError("Couldn't find \(filename) in Documents directory:\n\(error)")
    }
    
    do {
        let decoder = JSONDecoder()
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

func save(_ landmarks: [Landmark]) {
    let encoder = JSONEncoder()
    
    do {
        let data = try encoder.encode(landmarks)
        
        let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let fileURL = documentsURL.appendingPathComponent("landmarkData.json")
        
        do {
            try data.write(to: fileURL)
            print("Successfully wrote data to \(fileURL.path)")
        } catch {
            fatalError("Couldn't write to \(fileURL.path):\n\(error)")
        }
    } catch {
        fatalError("Couldn't encode landmarks as JSON:\n\(error)")
    }
}

func copyFileFromBundleToDocumentsFolder(sourceFile: String) {
    let fileManager = FileManager.default
    let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first!
    let destinationURL = documentsURL.appendingPathComponent(sourceFile)
    
    if !fileManager.fileExists(atPath: destinationURL.path) {
        if let sourceURL = Bundle.main.url(forResource: sourceFile, withExtension: nil) {
            do {
                try fileManager.copyItem(at: sourceURL, to: destinationURL)
                print("\(sourceFile) copied to Documents directory.")
            } catch {
                print("Error copying file: \(error)")
            }
        } else {
            print("Source file not found in bundle.")
        }
    }
}

但它既没有返回任何错误,也无法读取/写入文件,所以我假设它没有使用正确的路径。

提前致谢!

ios json swift
1个回答
0
投票

你说

guard let file = Bundle.main.url(forResource: "landmarkData.json", withExtension: nil)
然后你有
try data.write(to: file)
- 你正在尝试将数据写入应用程序包。您可以在模拟器上执行此操作,因为文件沙箱不是强制执行的,但在真实设备中,该捆绑包是只读的。

无论如何,这并不是您真正想要做的。您想要将其保存到

fileURL
位置:
try write(to: fileURL)

© www.soinside.com 2019 - 2024. All rights reserved.