【问题标题】:How to parse JSON using custom decoder init with incrementing keys in Swift如何在 Swift 中使用自定义解码器初始化和递增键来解析 JSON
【发布时间】:2020-10-08 15:32:24
【问题描述】:

我有一些餐点 json,我想将其转换为 MealData 结构

let randomMealJson = """
{
    "meals": [{
        "idMeal": "52812",
        "strMeal": "Beef Brisket Pot Roast",
        "strDrinkAlternate": null,
        "strCategory": "Beef",
        "strArea": "American",
        "strInstructions": "Meal instructions",
        "strMealThumb": "https://www.themealdb.com/images/media/meals/ursuup1487348423.jpg",
        "strTags": "Meat",
        "strYoutube": "https://www.youtube.com/watch?v=gh48wM6bPWQ",
        "strIngredient1": "Beef Brisket",
        "strIngredient2": "Salt",
        "strIngredient3": "Onion",
        "strIngredient4": "Garlic",
        "strIngredient5": "Thyme",
        "strIngredient6": "Rosemary",
        "strIngredient7": "Bay Leaves",
        "strIngredient8": "beef stock",
        "strIngredient9": "Carrots",
        "strIngredient10": "Mustard",
        "strIngredient11": "Potatoes",
        "strIngredient12": null,
        "strIngredient13": null,
        "strIngredient14": null,
        "strIngredient15": null,
        "strIngredient16": null,
        "strIngredient17": null,
        "strIngredient18": null,
        "strIngredient19": null,
        "strIngredient20": null,
        "strMeasure1": "4-5 pound",
        "strMeasure2": "Dash",
        "strMeasure3": "3",
        "strMeasure4": "5 cloves",
        "strMeasure5": "1 Sprig",
        "strMeasure6": "1 sprig ",
        "strMeasure7": "4",
        "strMeasure8": "2 cups",
        "strMeasure9": "3 Large",
        "strMeasure10": "1 Tbsp",
        "strMeasure11": "4 Mashed",
        "strMeasure12": "",
        "strMeasure13": "",
        "strMeasure14": "",
        "strMeasure15": "",
        "strMeasure16": "",
        "strMeasure17": "",
        "strMeasure18": "",
        "strMeasure19": "",
        "strMeasure20": "",
        "strSource": "http://www.simplyrecipes.com/recipes/beef_brisket_pot_roast/",
        "dateModified": null
    }]
}
"""

这是我想要制作的结构...

struct MealData: Decodable {
    let meals: [Meal]
}

struct Meal: Decodable {
    let items: [Item]
}

extension Meal {
    struct Item: Decodable {
        let ingredient: String
        let measure: String
    }
}

extension Meal {
    init(from decoder: Decoder) throws {
//        var items: [Item] = (0...20).map { num in      
//           what to do here?
//        }
    }
}

我想检查成分和措施,并从中创建一个Meal.Item,但我不知道如何实现这一点。可以按照我在代码中指出的方式吗?

【问题讨论】:

    标签: json swift decodable


    【解决方案1】:

    我会分两步完成。先解码成字典

    struct MealData: Decodable {
        let meals: [[String: String?]]
    }
    

    然后我会在单独的步骤中转换为另一种类型

    struct Recipie {
        var ingredients: [Ingredient]
    }
    
    struct Ingredient {
        let ingredient: String
        let measure: String
    }
    

    这是完整的代码

    do {
        let result = try JSONDecoder().decode(MealData.self, from: randomMealJson)
    
        var recipies = [Recipie]()
        for meal in result.meals {
            var recipie = Recipie(ingredients: [])
            var index = 1
            while true {
                guard let ingredientValue = meal["strIngredient\(index)"],
                      let measureValue = meal["strMeasure\(index)"],
                      let ingredient = ingredientValue,
                      let measure = measureValue, !measure.isEmpty
                else { break }
    
                recipie.ingredients.append(Ingredient(ingredient: ingredient, measure: measure))
                recipies.append(recipie)
                index += 1
            }
        }
    } catch {
        print(error)
    }
    

    【讨论】:

      【解决方案2】:

      按照@joakim-danielson 的回答。你可以在 init(from:) 初始化器中做同样的事情,就像你的初衷一样。

      只需将每个Meal 的成分和度量解码为[String: String?] 并编写您的自定义Items:

      extension Meal {
          init(from decoder: Decoder) throws {
              let container = try decoder.singleValueContainer()
              
              let mealDict = try container.decode([String: String?].self)
              var index = 1
              var items = [Item]()
              while
                  let ingredient = mealDict["strIngredient\(index)"] as? String,
                  let measure = mealDict["strMeasure\(index)"] as? String,
                  !measure.isEmpty
              {
                  items.append(Item(ingredient: ingredient, measure: measure))
                  index += 1
              }
              self.items = items
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2023-01-29
        • 2020-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多