如何使用前缀解码动态键?基于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
相关产品推荐
相关产品推荐

