Swift开发:在线JSON获取失败时如何解码本地备用JSON?
在线JSON获取失败时自动加载本地备用JSON的实现方案
修改思路
先尝试请求在线JSON文件,若出现网络错误、解码失败等问题,立即读取Xcode项目中存储的本地JSON文件进行解码,确保界面能正常显示数据。
修改后的完整代码
WineryModel.swift
import Foundation let onlineWineryURL = URL(string: "https://***/wineries.json") class WineryViewModel: ObservableObject { @Published var wineries: [Winery]? @Published var currentWinery: Winery? init(){ Task{ do{ try await fetchOnlineJsonData() }catch{ print("🚩 在线获取失败: " + error.localizedDescription) // 在线失败后尝试加载本地JSON do { try loadLocalJson() } catch { print("🚩 本地JSON加载也失败: " + error.localizedDescription) } } } } // 在线获取JSON数据 func fetchOnlineJsonData()async throws{ guard let url = onlineWineryURL else { throw NSError(domain: "InvalidURL", code: -1, userInfo: [NSLocalizedDescriptionKey: "在线JSON地址无效"]) } let session = URLSession.shared let (data, _) = try await session.data(from: url) let jsonData = try JSONDecoder().decode([Winery].self, from: data) await MainActor.run { updateWineryData(with: jsonData) } } // 加载本地JSON数据 func loadLocalJson() throws { // 替换成你本地JSON文件的名称(不带.json后缀) guard let localFileURL = Bundle.main.url(forResource: "wineries", withExtension: "json") else { throw NSError(domain: "LocalFileNotFound", code: -2, userInfo: [NSLocalizedDescriptionKey: "本地JSON文件未找到"]) } let data = try Data(contentsOf: localFileURL) let jsonData = try JSONDecoder().decode([Winery].self, from: data) DispatchQueue.main.async { self.updateWineryData(with: jsonData) } } // 统一更新数据的辅助方法 private func updateWineryData(with data: [Winery]) { self.wineries = data self.currentWinery = data.first } }
ContentView.swift(基础版本无需修改,可选添加错误提示优化)
import SwiftUI struct ContentView: View { @EnvironmentObject private var wineVM: WineryViewModel // 可选:添加错误弹窗提示用户 @State private var showErrorAlert = false @State private var errorTip = "" var body: some View { Group { if let wineries = wineVM.wineries, let currentWinery = wineVM.currentWinery { VStack { List { ForEach(wineries) { winery in Text(winery.name) } } } } else { ProgressView("加载中...") } } .alert(isPresented: $showErrorAlert) { Alert(title: Text("加载失败"), message: Text(errorTip), dismissButton: .default(Text("确定"))) } // 可选:如果需要把错误提示给用户,可以在ViewModel新增错误状态并监听 .onAppear { // 可根据需求扩展ViewModel的错误状态监听逻辑 } } }
关键说明
- 错误链路覆盖:拆分原在线请求方法,在初始化的错误捕获块中触发本地加载逻辑,覆盖了网络无连接、URL无效、解码失败等所有在线获取可能出现的异常。
- 本地文件读取:通过
Bundle.main.url(forResource:withExtension:)获取本地JSON路径,注意替换成你实际的本地文件名(比如本地文件叫local_wineries.json,就把参数改成"local_wineries")。 - 统一数据更新:新增
updateWineryData辅助方法,避免在线和本地加载的UI更新代码重复,保证逻辑一致性。 - 主线程安全:在线获取用
MainActor.run、本地加载用DispatchQueue.main.async,确保所有UI操作在主线程执行,符合SwiftUI的线程要求。
内容的提问来源于stack exchange,提问作者luegm.dev
相关产品推荐
相关产品推荐

