无法更新cacheDirectory中的JSON数据

vwkv1x7d  于 2023-04-22  发布在  其他
关注(0)|答案(1)|浏览(161)

已经过了一个星期了,我仍然不能弄清楚我的代码中缺少了什么。我只是想将JSON文件保存在我的本地cacheDirectory中,并将其加载回离线用户。我的代码能够从本地目录中保存和读回,但是如果我更新了GitHub存储库中的JSON数据,它就不起作用了。只有原始的JSON数据被加载,更新的JSON文件只有在我更改了一些代码并重新启动模拟器时才被加载。看起来没有覆盖代码来覆盖现有的JSON文件。
简单地说,我想将最新的JSON数据保存在本地目录中,并在每次对GitHub存储库进行更改时加载回来。例如,我用两个稍微不同的JSON链接进行了测试,通过注解掉这两个链接来查看更新的JSON。请帮助我解决我的代码中无法解决的问题。提前感谢。我的代码如下:

class FetchingJSONFile5 {
@Published var allSongs: [TuunoLabu] = []
@Published var isNewFile: Bool = true
let folderOne = "TuunoLabu_Folder1"

init() {
    
    createFolderOne()
    downloadJSON()
    
    if let lyrics = fetchTuunoLabu(from: "TuunoLabu") {
        allSongs = lyrics
    }
}

private func createFolderOne() {
    guard let directoryOne = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent(folderOne).relativePath else { return }
    
    if !FileManager.default.fileExists(atPath: directoryOne) {
        do {
            try FileManager.default.createDirectory(atPath: directoryOne, withIntermediateDirectories: true)
            print("Successfully created Folder One")
            //print(directoryOne)
        } catch let error {
            print("Error while creating Folder One", error)
        }
    }
}

private func downloadJSON() {
            
    guard let urlRequest = URL(string:
        // This JSON has id 1 to 748
        "https://raw.githubusercontent.com/siantung/TuunoLabu/fac87c9d6b63f5e52cadb8873fb0d77cd0fc91e1/JSON/TuunoLabu.json"
                               
        // This JSON has id 1 to 800
        //"https://raw.githubusercontent.com/siantung/Hymn-iOS/main/HymnSong(02-25-2023).json"
    )
    else {
        print("ERROR: Could not find the URL")
        return
    }
    
    guard let directory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
        .first?.appendingPathComponent(folderOne)
        .appendingPathComponent("TuunoLabu.json") else { return }
    
    //print(directory)
    
    let dataTask = URLSession.shared.dataTask(with: urlRequest) { [weak self] data, _, error in
        guard let data = data, error == nil else { return }
        
        do {
            
            try data.write(to: directory, options: .atomic)
            print("Successfully saved downloaded JSON new file.")
            self?.isNewFile = true
            
        } catch let error {
            print("Error decoding: ",error)
            self?.isNewFile = false
        }
    }
    dataTask.resume()
    
}

private func fetchTuunoLabu(from name: String) -> [TuunoLabu]? {

    guard let directoryOne = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask)
        .first?.appendingPathComponent(folderOne)
        .appendingPathComponent("TuunoLabu.json") else {
        print("Error to retrieve directory while fetching file")
        return nil
    }

    if FileManager.default.fileExists(atPath: directoryOne.relativePath) {
        do {

            let data = try Data(contentsOf: directoryOne)
            return try JSONDecoder().decode([TuunoLabu].self, from: data)

        } catch {
            print("Error JSON decoding: \(error)")
        }
    }
    return nil
  }

}
qvtsj1bj

qvtsj1bj1#

这是一个典型的计时问题。数据是异步下载的,fetchTuunoLabu的结果在URLSession的完成处理程序被调用之前被检索到。
在代码中,将表达式if let lyrics = ...放入完成处理程序中的try data.write之后,或者直接使用该数据
但是我建议利用async/await和Swift中的错误处理。
首先,用下面的方法替换createFolderOne。它返回缓存目录中给定文件名的文件的URL,如果不存在,则动态创建目录。可能的错误是thrown给调用者

private func cachedURL(fileName: String = "TuunoLabu.json") throws -> URL {
    let directoryOne = try FileManager.default.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        .appendingPathComponent(folderOne)
    if !FileManager.default.fileExists(atPath: directoryOne.path) {
        try FileManager.default.createDirectory(at: directoryOne, withIntermediateDirectories: true)
    }
    return directoryOne.appendingPathComponent(fileName)
}

downloadJSON方法可以简化为以下几行

private func downloadJSON() async throws {
    guard let url = URL(string:
        "https://raw.githubusercontent.com/siantung/TuunoLabu/fac87c9d6b63f5e52cadb8873fb0d77cd0fc91e1/JSON/TuunoLabu.json") else {
        throw URLError(.badURL)
    }
    
    let fileURL = try cachedURL()
    let (data, _) = try await URLSession.shared.data(from: url)
    try data.write(to: fileURL, options: .atomic)
    isNewFile = true
}

async的好处是,尽管数据是异步加载的,但该方法的行为类似于同步方法,而await是结果
第三种方法也包含几行

private func fetchTuunoLabu(from name: String) throws -> [TuunoLabu] {
    let fileURL = try cachedURL(fileName: name)
    let data = try Data(contentsOf: fileURL)
    return try JSONDecoder().decode([TuunoLabu].self, from: data)
}

其他同学都是

class FetchingJSONFile5 {
    @Published var allSongs: [TuunoLabu] = []
    @Published var isNewFile: Bool = true
    let folderOne = "TuunoLabu_Folder1"
    
    init() {
        Task {
            do {
                try await downloadJSON()
                allSongs = try fetchTuunoLabu(from: "TuunoLabu.json")
            } catch {
                isNewFile = false
                print(error)
                // or show something more significant to the user
            }
        }
    }

相关问题