Swift 4 Decodable - нет значения, связанного с ключом CodingKeys

Я расшифровываю ответ JSON в своем приложении Swift, и код работал до тех пор, пока не решил перестать работать.

это мой ответ json

{"foods":[{"food_name":"Milk Chocolate","brand_name":"Snickers","serving_weight_grams":41.7,"nf_calories":212.3,"nf_total_fat":11.6,"nf_saturated_fat":4,"nf_total_carbohydrate":22.7,"nf_protein":3.9}]}

И это код для декодирования моего json

let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        guard let data = data else { return }

        print(String(data: data, encoding: .utf8)!)
        do {
            //Decode dataResponse received from a network request
            let decoder = JSONDecoder()
            let foods = try decoder.decode(JSONFoods.self, from: data) //Decode JSON Response Data

            self.jsonfood = foods.JSONFood[0]
            print(self.jsonfood!)

        } catch let parsingError {
            print("Error", parsingError)
        }

    }
    task.resume()

И мои структуры

struct JSONFoods: Decodable {
var JSONFood: [JSONFood]    
}

struct JSONFood: Decodable{
var food_name: String
var brand_name: String
var nf_calories: Int
var nf_protein: Int
var nf_total_fat: Int
var nf_total_carbohydrate: Int
var serving_weight_grams: Int
}

И сообщение об ошибке, которое я получаю, это

keyNotFound(CodingKeys(stringValue: "JSONFood", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "Нет значения, связанного с ключом CodingKeys(stringValue: \"JSONFood\", intValue: nil) (\ "JSONFood\").", базовая ошибка: ноль))

И если я получаю замену decode(JSONFood.self, from: data) на decode(JSONFood.self, from: data), я получаю это сообщение об ошибке

keyNotFound(CodingKeys(stringValue: "food_name", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "Нет значения, связанного с ключом CodingKeys(stringValue: \"food_name\", intValue: nil) (\ "food_name\").", основная ошибка: ноль))

Я искал везде безуспешно, любая помощь очень ценится


person Stu-dying    schedule 07.04.2019    source источник


Ответы (1)


Тебе нужно

struct Root: Codable {
    let foods: [Food]
}

struct Food: Codable {
    let foodName: String?
    let  brandName: String
    let servingWeightGrams, nfCalories, nfTotalFat: Double
    let nfSaturatedFat: Int
    let nfTotalCarbohydrate, nfProtein: Double

    enum CodingKeys: String, CodingKey {
        case foodName = "food_name"
        case brandName = "brand_name"
        case servingWeightGrams = "serving_weight_grams"
        case nfCalories = "nf_calories"
        case nfTotalFat = "nf_total_fat"
        case nfSaturatedFat = "nf_saturated_fat"
        case nfTotalCarbohydrate = "nf_total_carbohydrate"
        case nfProtein = "nf_protein"
    }
}

Во-первых: вы делаете JSONFood, хотя должно быть foods

Во-вторых:food_name не существует в текущем корне json, поэтому это не удастся

let foods = try decoder.decode(JSONFoods.self, from: data) //Decode JSON Response Data

На случай, если вы воспользуетесь convertFromSnakeCase

let str = """

{"foods":[{"food_name":"Milk Chocolate","brand_name":"Snickers","serving_weight_grams":41.7,"nf_calories":212.3,"nf_total_fat":11.6,"nf_saturated_fat":4,"nf_total_carbohydrate":22.7,"nf_protein":3.9}]}

"""

    do {
        let res = JSONDecoder()
        res.keyDecodingStrategy = .convertFromSnakeCase
        let ss = try res.decode(Root.self, from:Data(str.utf8))
        print(ss)
    }
    catch {
        print(error)
    }

struct Root: Codable {
    let foods: [Food]
}

struct Food: Codable {
    let foodName: String?
    let  brandName: String
    let servingWeightGrams, nfCalories, nfTotalFat: Double
    let nfSaturatedFat: Int
    let nfTotalCarbohydrate, nfProtein: Double
}
person Sh_Khan    schedule 07.04.2019
comment
Нет необходимости переименовывать структуру JSONFoods в Root. - person rmaddy; 07.04.2019
comment
я делаю это на случай, если есть несколько структур для выделения базовой модели - person Sh_Khan; 07.04.2019
comment
Вторая ошибка в вопросе возникает из-за того, что OP декодирует дочернюю структуру JSONFood как корневой объект. Это не имеет никакого отношения к тому, что food_name может отсутствовать. И почему бы вам не предложить .convertFromSnakeCase стратегию избавления от CodingKeys? - person vadian; 07.04.2019
comment
я просто редактирую это перед комментарием :), и да, я согласен, что случай со змеей лучше, но динамическая генерация сайта может не принимать это во внимание на данный момент = D - person Sh_Khan; 07.04.2019