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

Swift新手求助:如何正确处理JSON解析错误?

解决Swift中URLSession请求的错误处理问题

Hey there! Let's figure out why your catch block isn't working and fix this properly.

问题根源

你遇到的两个核心问题:

  • try!导致错误无法抛出:try!是强制解码,一旦解码失败会直接触发运行时崩溃,而不是把错误抛给catch块处理。这也是编译器提示“catch块不可达”的原因——它看到你用了try!,认定do块里不会抛出任何可被捕获的错误。
  • data!强制解包直接崩溃:如果API请求失败(比如超时、网络错误),data会是nil,这时候data!会直接崩溃,根本到不了do-catch的逻辑。

修复方案

我们需要分步骤处理所有可能的错误场景,同时用正确的方式抛出/捕获错误。

1. 定义自定义错误类型(可选但推荐)

先定义一个枚举来统一管理不同类型的错误,让错误处理更清晰:

enum APIError: Error {
    case noDataReceived          // 请求成功但没返回数据
    case requestFailed(Error)    // 请求本身失败(比如网络问题)
    case decodingFailed(Error)   // JSON解码失败
}

2. 修改请求处理逻辑

调整你的dataTask代码,完整处理所有错误分支:

// 假设你的completion闭包类型更新为Result类型,更规范
func fetchFiatRates(completion: @escaping (Result<FiatResponse, APIError>) -> Void) {
    guard let url = URL(string: "你的API地址") else {
        DispatchQueue.main.async {
            completion(.failure(.requestFailed(NSError(domain: "InvalidURL", code: -1, userInfo: nil))))
        }
        return
    }
    
    URLSession.shared.dataTask(with: url) { data, _, error in
        // 第一步:处理请求本身的错误(比如超时、无网络)
        if let requestError = error {
            DispatchQueue.main.async {
                completion(.failure(.requestFailed(requestError)))
            }
            return
        }
        
        // 第二步:确保data不为nil
        guard let responseData = data else {
            DispatchQueue.main.async {
                completion(.failure(.noDataReceived))
            }
            return
        }
        
        // 第三步:安全解码JSON,用try代替try!
        do {
            let fiatRates = try JSONDecoder().decode(FiatResponse.self, from: responseData)
            DispatchQueue.main.async {
                completion(.success(fiatRates))
            }
        } catch let decodingError {
            DispatchQueue.main.async {
                completion(.failure(.decodingFailed(decodingError)))
            }
        }
    }.resume()
}

3. 调用时的错误处理

当你调用这个方法时,就可以优雅地处理所有情况了:

fetchFiatRates { result in
    switch result {
    case .success(let rates):
        // 处理成功拿到的数据
        print("Rates: \(rates.rates)")
    case .failure(let error):
        // 根据错误类型做对应处理
        switch error {
        case .noDataReceived:
            print("请求成功但未收到数据")
        case .requestFailed(let underlyingError):
            print("请求失败:\(underlyingError.localizedDescription)")
        case .decodingFailed(let underlyingError):
            print("JSON解码失败:\(underlyingError.localizedDescription)")
        }
    }
}

关键要点总结

  • 永远避免用try!和强制解包!处理网络请求相关的可选值,这些操作会把可恢复的错误变成致命崩溃。
  • 必须先处理URLSession返回的error参数,这是捕获网络层错误的关键。
  • 用try配合do-catch来处理解码错误,这样错误会被正确抛到catch块中处理。
  • 所有UI相关的更新(包括completion回调)都要放在主队列DispatchQueue.main.async中执行。

内容的提问来源于stack exchange,提问作者Reyraa

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:26:01