无法更新cacheDirectory中JSON数据,GitHub更新后本地缓存未同步
问题解决:本地缓存JSON无法自动同步GitHub更新数据
核心问题分析
你的代码存在三个关键问题导致无法自动加载最新JSON:
- 异步任务执行顺序错误:初始化时先启动异步的
downloadJSON,立刻同步读取本地缓存,此时下载还未完成,加载的始终是旧数据。 - 下载完成后未更新数据源:即使新JSON下载成功,也没有重新读取文件并更新
allSongs,只有重启时才会重新读取。 - URLSession默认缓存:默认情况下URLSession会缓存请求结果,即使GitHub上的JSON更新了,依然可能拿到旧的缓存响应。
修复后的完整代码
class FetchingJSONFile5 { @Published var allSongs: [TuunoLabu] = [] @Published var isNewFile: Bool = true let folderOne = "TuunoLabu_Folder1" init() { createFolderOne() // 先加载本地缓存保证离线可用,再启动下载任务更新最新数据 if let lyrics = fetchTuunoLabu(from: "TuunoLabu") { allSongs = lyrics } downloadJSON() } 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") } catch let error { print("Error while creating Folder One", error) } } } private func downloadJSON() { guard let url = URL(string: "https://raw.githubusercontent.com/siantung/TuunoLabu/fac87c9d6b63f5e52cadb8873fb0d77cd0fc91e1/JSON/TuunoLabu.json") else { print("ERROR: Could not find the URL") return } // 构建请求,禁用本地缓存,确保获取最新数据 var urlRequest = URLRequest(url: url) urlRequest.cachePolicy = .reloadIgnoringLocalCacheData guard let directory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask) .first?.appendingPathComponent(folderOne) .appendingPathComponent("TuunoLabu.json") else { return } let dataTask = URLSession.shared.dataTask(with: urlRequest) { [weak self] data, response, error in guard let data = data, error == nil else { print("Download error: \(error?.localizedDescription ?? "Unknown error")") self?.isNewFile = false return } // 验证响应状态码,避免错误响应覆盖本地缓存 guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { print("Invalid response status code") self?.isNewFile = false return } do { try data.write(to: directory, options: .atomic) print("Successfully saved downloaded JSON new file.") // 下载完成后,在主队列更新数据源(@Published属性必须在主线程修改) if let lyrics = self?.fetchTuunoLabu(from: "TuunoLabu") { DispatchQueue.main.async { self?.allSongs = lyrics self?.isNewFile = true } } } catch let error { print("Error saving file: ",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 } }
关键修改点说明
- 调整初始化逻辑:优先加载本地缓存保证离线用户正常使用,再触发下载任务拉取最新数据。
- 强制跳过本地缓存:通过设置
urlRequest.cachePolicy = .reloadIgnoringLocalCacheData,确保每次请求都从GitHub获取最新JSON。 - 下载完成后实时更新数据:文件写入成功后,重新读取本地文件并在主队列更新
allSongs,保证UI能实时刷新最新内容。 - 增加响应校验:验证HTTP状态码,避免错误的响应内容覆盖本地有效缓存。
进阶优化建议
如果想减少不必要的网络请求,可以:
- 记录本地文件的
Last-Modified时间,请求时通过If-Modified-Since请求头询问服务器是否有更新,仅当文件变更时才下载。 - 存储GitHub返回的
ETag值,对比本地ETag,只有不一致时才执行下载操作。
内容的提问来源于stack exchange,提问作者Lian
相关产品推荐
相关产品推荐

