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

Swift Codable解析带动态键的JSON响应时第二个对象解析为nil问题

问题原因
  1. 你在自定义解码逻辑中使用try?静默吞掉了RelatedProductPrice类型的解码错误,无法定位具体失败点。从现象来看大概率是RelatedProductPrice的字段映射不匹配(例如下划线格式的JSON键和驼峰格式的属性名没有正确映射、字段类型定义错误),刚好第一个对象符合映射规则,第二个对象映射失败。
  2. 手写的动态键解码逻辑冗余,且DynamicCodingKeys的整型初始化方法直接返回nil,存在潜在的数字类型键解析异常风险。
解决方案

方案1:简化模型,无需手写自定义解码逻辑

直接用[String: RelatedProductPrice]数组承接related_product_price_info的内容,完全避开自定义解码的出错概率:
首先定义基础价格模型:

struct RelatedProductPrice: Codable {
    let price: Double
    let discountPercentage: Double
    let relatedProductGroupId: Int
    let discountedPrice: Double
    
    enum CodingKeys: String, CodingKey {
        case price
        case discountPercentage = "discount_percentage"
        case relatedProductGroupId = "related_product_group_id"
        case discountedPrice = "discounted_price"
    }
}

修改根模型定义:

struct ProductSearchResult: Codable {
    let searchResult: String?
    let relatedProductPriceInfo: [[String: RelatedProductPrice]]?
    
    enum CodingKeys: String, CodingKey {
        case searchResult = "search_result"
        case relatedProductPriceInfo = "related_product_price_info"
    }
}

解析代码(显式捕获错误,方便定位问题):

let decoder = JSONDecoder()
// 如果所有字段都要自动转换下划线到驼峰,也可以开启这个配置,不需要单独写CodingKeys
// decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
    let result = try decoder.decode(ProductSearchResult.self, from: data)
    // 取值示例
    result.relatedProductPriceInfo?.forEach { itemDict in
        guard let (groupId, priceInfo) = itemDict.first else { return }
        print("动态键:\(groupId),价格数据:\(priceInfo)")
    }
} catch {
    // 解码出错会打印具体错误信息,直接定位问题字段
    print("解码失败:\(error)")
}

方案2:保留原有模型结构,修复解码逻辑

如果需要保留RelatedProductPriceInfo的封装结构,修改其自定义解码实现,不要静默吞错,同时修复DynamicCodingKeys的实现:

struct RelatedProductPriceInfo: Codable {
    var relatedProductPrice: RelatedProductPrice?
    
    private struct DynamicCodingKeys: CodingKey {
        var stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        // 修复整型键的初始化逻辑,避免数字类动态键解析失败
        var intValue: Int?
        init?(intValue: Int) {
            self.stringValue = "\(intValue)"
            self.intValue = intValue
        }
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DynamicCodingKeys.self)
        guard let firstKey = container.allKeys.first else { return }
        // 不要用try?,出错直接抛出,方便排查
        relatedProductPrice = try container.decode(RelatedProductPrice.self, forKey: firstKey)
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 07:45:03