Swift中使用async/await异步解码API JSON数据时出现解码错误
问题排查与解决方案
核心问题根源
你遇到的解码失败,是因为API返回的部分条目里ISIN字段为null,但你的Quote结构体中isin被定义为非可选的String类型。Swift的Codable协议要求非可选类型必须对应JSON中的非空值,当遇到null时无法完成解码,直接抛出valueNotFound错误。
错误日志里的Index 3明确指向第4条数据的ISIN字段为null,导致整个数组解码失败。
解决方案步骤
1. 修改结构体字段为可选类型
将Quote中的isin改为可选的String?,允许其接收JSON中的null值:
struct Quote: Codable, Identifiable { var id: UUID { return UUID() } let code: String let exchange: String let name: String let type: String let isin: String? // 改为可选类型 let price: Double let closeDate: String let country: String let currency: String private enum CodingKeys: String, CodingKey { case code = "Code" case exchange = "Exchange" case name = "Name" case type = "Type" case isin = "ISIN" case price = "previousClose" case closeDate = "previousCloseDate" case country = "countryName" case currency = "currencyCode" } }
2. 优化错误处理逻辑
你当前用try?吞掉了所有解码错误,导致无法看到具体问题。建议改为do-catch捕获并打印详细错误,方便后续调试:
// 替换原解码代码段 let decoder = JSONDecoder() do { let securities = try decoder.decode([Quote].self, from: data) self.searchResults = securities } catch { print("解码详细错误:\(error)") self.error = error return }
3. 可选:给空字段设置默认值
如果业务上不希望isin为nil,可以自定义解码方法,给null的ISIN设置默认值(比如空字符串):
struct Quote: Codable, Identifiable { var id: UUID { return UUID() } let code: String let exchange: String let name: String let type: String let isin: String // 保持非可选 let price: Double let closeDate: String let country: String let currency: String private enum CodingKeys: String, CodingKey { case code = "Code" case exchange = "Exchange" case name = "Name" case type = "Type" case isin = "ISIN" case price = "previousClose" case closeDate = "previousCloseDate" case country = "countryName" case currency = "currencyCode" } // 自定义解码初始化方法 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) code = try container.decode(String.self, forKey: .code) exchange = try container.decode(String.self, forKey: .exchange) name = try container.decode(String.self, forKey: .name) type = try container.decode(String.self, forKey: .type) // 若ISIN为null,默认空字符串 isin = try container.decodeIfPresent(String.self, forKey: .isin) ?? "" price = try container.decode(Double.self, forKey: .price) closeDate = try container.decode(String.self, forKey: .closeDate) country = try container.decode(String.self, forKey: .country) currency = try container.decode(String.self, forKey: .currency) } }
额外检查建议
排查API返回的其他字段是否也存在null的可能(比如previousClose),如果有,同样需要将对应结构体字段改为可选类型或设置默认值,避免后续出现类似解码错误。
内容的提问来源于stack exchange,提问作者SPR
相关产品推荐
相关产品推荐

