Swift实现从Web服务器下载JSON文件本地存储适配弱网环境
Swift解决方案:下载JSON文件到本地实现离线访问
当然可以!我给你整理了一套实用的Swift实现方案,完美解决你的需求——把Web服务器上的JSON文件下载到本地存储,用户后续就能直接读取本地文件,再也不用每次受网络波动困扰了:
1. 封装核心工具类
先写一个单例工具类JSONFileManager,把下载、存储、读取的逻辑都封装在这里,方便复用:
import Foundation enum JSONFileError: Error { case invalidURL case downloadFailed case saveFailed case fileNotFound } class JSONFileManager { static let shared = JSONFileManager() private let fileManager = FileManager.default // 获取应用Documents目录路径(用于存储JSON文件) private func getDocumentsDirectory() -> URL { let paths = fileManager.urls(for: .documentDirectory, in: .userDomainMask) return paths[0] } // 下载并保存JSON文件到本地(优先读取本地缓存) func downloadAndSaveJSON(from url: URL, completion: @escaping (Result<Data, JSONFileError>) -> Void) { // 先检查本地是否已有文件,如果有直接返回本地数据 let localFilePath = getDocumentsDirectory().appendingPathComponent(url.lastPathComponent) if fileManager.fileExists(atPath: localFilePath.path) { do { let data = try Data(contentsOf: localFilePath) completion(.success(data)) return } catch { completion(.failure(.fileNotFound)) return } } // 本地无文件,发起网络下载 let task = URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let self = self else { return } if let error = error { print("下载出错:\(error.localizedDescription)") completion(.failure(.downloadFailed)) return } guard let data = data else { completion(.failure(.downloadFailed)) return } // 将下载的数据写入本地文件 do { try data.write(to: localFilePath) completion(.success(data)) } catch { print("保存文件出错:\(error.localizedDescription)") completion(.failure(.saveFailed)) } } task.resume() } // 手动读取本地JSON文件(如果需要单独调用) func loadLocalJSON(named fileName: String) -> Result<Data, JSONFileError> { let localFilePath = getDocumentsDirectory().appendingPathComponent(fileName) guard fileManager.fileExists(atPath: localFilePath.path) else { return .failure(.fileNotFound) } do { let data = try Data(contentsOf: localFilePath) return .success(data) } catch { return .failure(.fileNotFound) } } }
2. 补充网络状态检测(可选但实用)
如果想优化体验——比如网络正常时自动更新本地文件,无网络时直接用缓存,可以加个简单的网络状态检测:
import Network class NetworkMonitor { static let shared = NetworkMonitor() private let monitor = NWPathMonitor() private(set) var isConnected: Bool = false private init() { monitor.pathUpdateHandler = { path in self.isConnected = path.status == .satisfied } let queue = DispatchQueue(label: "NetworkMonitor") monitor.start(queue: queue) } }
之后可以在工具类的下载逻辑里加入判断:如果无网络且本地无文件,就返回明确的错误提示,引导用户检查网络。
3. 实际使用示例
在你的ViewModel或者ViewController里,这样调用就能实现「优先读本地,无本地则下载」的逻辑:
// 替换成你的JSON文件服务器地址 guard let jsonURL = URL(string: "https://your-server-address/example.json") else { print("无效的URL") return } JSONFileManager.shared.downloadAndSaveJSON(from: jsonURL) { result in DispatchQueue.main.async { // 回到主线程更新UI switch result { case .success(let jsonData): // 解析JSON到你的数据模型 do { let yourDataModel = try JSONDecoder().decode(YourCustomModel.self, from: jsonData) // 这里更新你的UI,比如刷新列表、展示数据 print("数据加载成功:\(yourDataModel)") } catch { print("JSON解析失败:\(error.localizedDescription)") } case .failure(let error): // 根据错误类型提示用户 switch error { case .fileNotFound: print("本地无缓存且网络不可用,请检查网络连接") default: print("数据加载失败:\(error)") } } } }
额外优化建议
- 缓存过期策略:可以给本地文件添加时间戳,比如超过7天就自动重新下载,避免数据太旧
- 文件命名规则:如果你的JSON文件没有固定文件名,可以用请求URL的MD5值作为本地文件名,避免冲突
- 错误提示本地化:把错误提示改成用户易懂的本地化文字,提升体验
内容的提问来源于stack exchange,提问作者Curtis
相关产品推荐
相关产品推荐

