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

Swift中do-try-catch二次解码自定义结构体出现编译错误如何解决?

问题原因

URLSession.shared.dataTask的回调闭包是不允许抛出未处理的错误的非抛错类型(Data?, URLResponse?, Error?) -> Void。你的代码里第二个try decoder.decode(ErrorInfoWithErrorCode.self, from: data)没有被do-catch包裹,它抛出的错误会向上穿透整个闭包,导致编译器判定这个闭包是抛错类型,和系统要求的类型不匹配,触发编译错误。

解决方案

方案1:调整do-catch结构,包裹所有可能抛错的try

把第二次解码逻辑也放到独立的do-catch块中处理即可,修改后的代码如下:

struct ErrorInfo: Codable {
    public let message: String?
    public let details: String?
    public let debugInformation: String?
}

struct ErrorInfoWithErrorCode: Codable {
    public let message: [String: Int]
    public let details: String?
    public let debugInformation: String?
}

let request = URLRequest(url: URL(string: "https://www.google.com/")!)
let decoder = JSONDecoder() // 原代码漏了decoder初始化,此处补上

let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let httpResponse = response as? HTTPURLResponse, !(200..<300).contains(httpResponse.statusCode), let data = data {
        do {
            // 先尝试解码为message是String的结构
            let errorMessage = try decoder.decode(ErrorInfo.self, from: data)
            print(errorMessage)
        } catch  {
            do {
                // 第一次解码失败,尝试第二种结构
                let errorMessage = try decoder.decode(ErrorInfoWithErrorCode.self, from: data)
                print(errorMessage)
            } catch {
                // 两次都失败的处理逻辑,不要用fatalError,线上环境会触发崩溃
                print("未知错误格式:\(error.localizedDescription)")
            }
        }
    }
}
task.resume()

方案2:更优雅的实现:合并两个结构体,兼容两种message类型

你可以直接定义一个枚举适配两种类型的message,不需要写两个独立的Codable结构体,代码更简洁易维护:

enum MessageType: Codable {
    case string(String)
    case dict([String: Int])
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let str = try? container.decode(String.self) {
            self = .string(str)
        } else if let dict = try? container.decode([String: Int].self) {
            self = .dict(dict)
        } else {
            throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath, debugDescription: "message字段类型不支持"))
        }
    }
}

struct UnifiedErrorInfo: Codable {
    public let message: MessageType
    public let details: String?
    public let debugInformation: String?
}

let request = URLRequest(url: URL(string: "https://www.google.com/")!)
let decoder = JSONDecoder()

// 使用时只需要解码一次
let task = URLSession.shared.dataTask(with: request) { data, response, error in
    if let httpResponse = response as? HTTPURLResponse, !(200..<300).contains(httpResponse.statusCode), let data = data {
        guard let errorInfo = try? decoder.decode(UnifiedErrorInfo.self, from: data) else {
            print("解码失败")
            return
        }
        // 根据message类型做不同处理
        switch errorInfo.message {
        case .string(let str):
            print("错误信息:\(str)")
        case .dict(let dict):
            print("错误码字典:\(dict)")
        }
    }
}
task.resume()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 19:06:04