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

使用Codable解析含动态键的JSON数据问题求助

动态键名场景下的Codable模型实现

当JSON中某字段的键名动态变化且非数组时,核心解决思路是用字典类型承接动态键值对,同时保留Codable的类型安全特性。以下是具体实现方案:

1. 定义子项结构体

先把动态键对应的统一子数据结构定义为Codable结构体。假设你的JSON示例结构如下(可根据实际调整):

{
  "code": 200,
  "data": {
    "dynamic_key_001": {"title": "商品A", "price": 99},
    "dynamic_key_002": {"title": "商品B", "price": 199}
  }
}

对应的子项结构体:

struct Product: Codable {
    let title: String
    let price: Int
}

2. 定义顶层响应模型

将data字段声明为[String: Product]类型,这样就能适配任意动态键名:

struct ApiResponse: Codable {
    let code: Int
    let data: [String: Product]
}

3. 解析本地JSON文件示例

// 读取本地JSON文件
guard let fileURL = Bundle.main.url(forResource: "sample", withExtension: "json"),
      let jsonData = try? Data(contentsOf: fileURL) else {
    print("读取本地JSON失败")
    return
}

// 解析模型
do {
    let response = try JSONDecoder().decode(ApiResponse.self, from: jsonData)
    // 遍历动态键值对
    for (key, product) in response.data {
        print("键名:\(key),商品名:\(product.title),价格:\(product.price)")
    }
} catch {
    print("解析错误:\(error.localizedDescription)")
}

特殊场景处理

如果动态键对应的子结构不统一(比如有的子项有title,有的有desc),可以选择两种方式:

  • 方式一:用[String: [String: Any]]作为data类型,但会失去类型安全,仅适用于临时调试。
  • 方式二:自定义Codable解析逻辑,在init(from decoder: Decoder)中根据子结构的特征判断解析类型,示例如下:
struct ApiResponse: Codable {
    let code: Int
    let data: [String: BaseItem]
    
    enum CodingKeys: String, CodingKey {
        case code, data
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        code = try container.decode(Int.self, forKey: .code)
        
        let dataContainer = try container.container(keyedBy: DynamicCodingKey.self, forKey: .data)
        var items = [String: BaseItem]()
        
        for key in dataContainer.allKeys {
            let keyString = key.stringValue
            if let product = try? dataContainer.decode(Product.self, forKey: key) {
                items[keyString] = product
            } else if let article = try? dataContainer.decode(Article.self, forKey: key) {
                items[keyString] = article
            }
        }
        data = items
    }
}

// 动态CodingKey实现
struct DynamicCodingKey: CodingKey {
    let stringValue: String
    init?(stringValue: String) {
        self.stringValue = stringValue
    }
    
    var intValue: Int?
    init?(intValue: Int) {
        return nil
    }
}

// 不同子项结构体
protocol BaseItem: Codable {}
struct Product: BaseItem { let title: String; let price: Int }
struct Article: BaseItem { let desc: String; let readCount: Int }

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 05:35:17