You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的错误状态监听逻辑
        }
    }
}

关键说明

  1. 错误链路覆盖:拆分原在线请求方法,在初始化的错误捕获块中触发本地加载逻辑,覆盖了网络无连接、URL无效、解码失败等所有在线获取可能出现的异常。
  2. 本地文件读取:通过Bundle.main.url(forResource:withExtension:)获取本地JSON路径,注意替换成你实际的本地文件名(比如本地文件叫local_wineries.json,就把参数改成"local_wineries")。
  3. 统一数据更新:新增updateWineryData辅助方法,避免在线和本地加载的UI更新代码重复,保证逻辑一致性。
  4. 主线程安全:在线获取用MainActor.run、本地加载用DispatchQueue.main.async,确保所有UI操作在主线程执行,符合SwiftUI的线程要求。

内容的提问来源于stack exchange,提问作者luegm.dev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 21:20:43