I have a JSON object which I want to decode into a struct. The JSON has similar key:value pairs for ingredients and measurements. I'd like to condense the ingredient and measurement information into an array or pair of arrays in my struct.
I'm not sure how to loop through the data using CodingKeys and a custom decoder to build the array. I want to avoid creating multiple properties in my struct for each ingredient and measurement. Same for the CodingKeys; I want to avoid creating multiple cases for ingredient1, ..2, ..3, and so on.
I've tried using associated values in the CodingKeys enum and using a singleValueContainer. I get an assortment of errors that I'm not quite able to parse through.
Below is sample code and a sample of the JSON data.
JSON Sample
{
"meal: [
{
"strMeal" : "name1",
"ingredient1": "abc",
"ingredient2": "efg",
"measurement1: "m1",
"measurement2": "m2",
}
]
}
struct Recipe: Decodable {
var id: String
var name: String
var category: String
var cuisine: String
var instructions: String
var imageURL: URL
var ingredients: [Ingredient]
// Could also be set up as var ingredients: [String] and var measurements: [String]
struct Ingredient {
var ingredient: String
var quantity: String
}
enum RecipeCodingKeys: String, CodingKey {
case id = "idMeal"
case name = "strMeal"
case category = "strCategory"
case cuisine = "strArea"
case instructions = "strInstructions"
case imageUrl = "strMealThumb"
// Not sure what case to include to address all variations of ingredient<#> and measurement<#>
}
enum RootCodingKeys: String, CodingKey {
case meals
}
init(from decoder: Decoder) throws {
let rootContainer = try decoder.container(keyedBy: RootCodingKeys.self)
var arrayContainer = try rootContainer.nestedUnkeyedContainer(forKey: .meals)
let propertiesContainer = try arrayContainer.nestedContainer(keyedBy: RecipeCodingKeys.self)
self.id = try propertiesContainer.decode(String.self, forKey: .id)
self.name = try propertiesContainer.decode(String.self, forKey: .name)
self.category = try propertiesContainer.decode(String.self, forKey: .category)
self.cuisine = try propertiesContainer.decode(String.self, forKey: .cuisine)
self.instructions = try propertiesContainer.decode(String.self, forKey: .instructions)
self.imageURL = try propertiesContainer.decode(URL.self, forKey: .imageUrl)
self.ingredients = ???
}
}
try this approach using a
whileloop:Have a look at my test code on github using the
themealdb: https://github.com/workingDog/FreeMeal/tree/main