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

如何使用前缀解码动态键?基于Decodable与Coding Keys实现数组转换

如何通过Decodable将带数字后缀的JSON字段解码为数组

实现思路

针对JSON中strIngredientX、strMeasureX这类带数字后缀的字段,可通过动态生成CodingKey的方式,循环提取有效数据并整理为数组,同时自动过滤空值或无效内容。

完整代码实现

首先定义对应的解码模型:

// 顶层响应模型,包裹餐品数组
struct MealResponse: Decodable {
    let meals: [Meal]
}

// 餐品模型,包含自定义数组字段
struct Meal: Decodable {
    // 常规字段
    let idMeal: String
    let strMeal: String
    let strCategory: String?
    let strArea: String?
    let strInstructions: String?
    let strMealThumb: String?
    let strYoutube: String?
    let strSource: String?
    
    // 自定义数组:存储提取后的成分和度量
    let ingredients: [String]
    let measures: [String]
    
    // CodingKeys仅声明固定字段,动态字段通过字符串拼接生成
    enum CodingKeys: String, CodingKey {
        case idMeal, strMeal, strCategory, strArea, strInstructions, strMealThumb, strYoutube, strSource
    }
    
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // 解码固定字段
        idMeal = try container.decode(String.self, forKey: .idMeal)
        strMeal = try container.decode(String.self, forKey: .strMeal)
        strCategory = try container.decodeIfPresent(String.self, forKey: .strCategory)
        strArea = try container.decodeIfPresent(String.self, forKey: .strArea)
        strInstructions = try container.decodeIfPresent(String.self, forKey: .strInstructions)
        strMealThumb = try container.decodeIfPresent(String.self, forKey: .strMealThumb)
        strYoutube = try container.decodeIfPresent(String.self, forKey: .strYoutube)
        strSource = try container.decodeIfPresent(String.self, forKey: .strSource)
        
        // 初始化临时数组,存储有效数据
        var ingredientsArray = [String]()
        var measuresArray = [String]()
        
        // 遍历1-20(对应JSON中最多20组成分/度量)
        for index in 1...20 {
            // 动态生成成分字段的CodingKey
            guard let ingredientKey = CodingKeys(stringValue: "strIngredient\(index)") else { continue }
            if let ingredient = try container.decodeIfPresent(String.self, forKey: ingredientKey), 
               !ingredient.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                ingredientsArray.append(ingredient)
            }
            
            // 动态生制度量字段的CodingKey
            guard let measureKey = CodingKeys(stringValue: "strMeasure\(index)") else { continue }
            if let measure = try container.decodeIfPresent(String.self, forKey: measureKey), 
               !measure.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                measuresArray.append(measure)
            }
        }
        
        // 赋值给模型属性
        ingredients = ingredientsArray
        measures = measuresArray
    }
}

关键细节说明

  • 动态CodingKey生成:通过CodingKeys(stringValue:)方法拼接数字后缀生成对应字段的key,无需在枚举中逐个声明所有strIngredientX/strMeasureX。
  • 空值过滤:使用trimmingCharacters(in: .whitespacesAndNewlines)去除空白字符后判断是否为空,避免将空字符串或纯空格内容加入数组。
  • 可选字段处理:使用decodeIfPresent解码可能为null的字段,避免解码失败崩溃。

内容的提问来源于stack exchange,提问作者j.doe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 18:35:17