GOOGLE ADS

miércoles, 27 de abril de 2022

Error de decodificación de Swift: no se encontró la clave al decodificar JSON

Estoy decodificando una respuesta JSON en mi aplicación Swift, y el código decidió no funcionar cuando cambié la URL de API.

Esta es mi respuesta json

{
"foodSearchCriteria":{
"query":"eggs",
"generalSearchInput":"eggs",
"pageNumber":1,
"numberOfResultsPerPage":50,
"pageSize":50,
"requireAllWords":false
},
"foods":[
{
"fdcId":577532,
"description":"EGGS",
"lowercaseDescription":"eggs",
"dataType":"Branded",
"gtinUpc":"021130049134",
"publishedDate":"2019-04-01",
"brandOwner":"Safeway, Inc.",
"ingredients":"",
"marketCountry":"United States",
"foodCategory":"Eggs & Egg Substitutes",
"modifiedDate":"2017-07-14",
"dataSource":"LI",
"servingSizeUnit":"g",
"servingSize":44.0,
"householdServingFullText":"1 EGG",
"allHighlightFields":"",
"score":848.0136,

}

Me encuentro con este error.

Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "foods", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"foods\", intValue: nil) (\"foods\").", underlyingError: nil))

Supuse que era porque no estaba haciendo coincidir mi var de "alimentos" correctamente, pero no aparece de esa manera. A continuación, adjunté fragmentos de mi llamada y estructuras.

 struct APISearchResults: Codable {
let currentPage, totalPages: Int?
let pageList: [Int]?
//let foodSearchCriteria: FoodSearchCriteria
let foods: [Food]

}
// MARK: - Food
struct Food: Codable { //core
let fdcID: Int
let foodDescription, lowercaseDescription, commonNames, additionalDescriptions: String?
let dataType: String?
let ndbNumber: Int?
let publishedDate, foodCategory, allHighlightFields: String?
let score: Double?
let foodNutrients: [FoodNutrientInformation]
let gtinUpc: Double?
let brandOwner: String?
let ingredients: String?
let marketCountry: String?
let modifiedDate: String?
let dataSource: String?
let servingSize: Double?
let householdServingFullText: String?


enum CodingKeys: String, CodingKey {
case fdcID = "fdcId"
case foodDescription = "description"
case lowercaseDescription, commonNames, additionalDescriptions, dataType, ndbNumber, publishedDate, foodCategory, allHighlightFields, score, foodNutrients, gtinUpc, brandOwner, ingredients, marketCountry, modifiedDate, dataSource, servingSize, householdServingFullText
}
}
// MARK: - FoodNutrient
struct FoodNutrientInformation: Codable {
let nutrientID: Int?
let nutrientName, nutrientNumber, unitName, derivationCode: String
let derivationDescription: String?
let derivationID: Int?
let value: Double?
let foodNutrientSourceID: Int?
let foodNutrientSourceCode, foodNutrientSourceDescription: String?
let rank, indentLevel, foodNutrientID, dataPoints: Int?
enum CodingKeys: String, CodingKey {
case nutrientID = "nutrientId"
case nutrientName, nutrientNumber, unitName, derivationCode, derivationDescription
case derivationID = "derivationId"
case value
case foodNutrientSourceID = "foodNutrientSourceId"
case foodNutrientSourceCode, foodNutrientSourceDescription, rank, indentLevel
case foodNutrientID = "foodNutrientId"
case dataPoints
}
}

Para fines de detalle, también adjuntaré la llamada API en sí misma en caso de que esté relacionada con eso.

class FoodApiSearch: ObservableObject{
@Published var foodDescription = ""
@Published var foodUnit = ""
@Published var calories = ""

//will search for user Input
func searchFood(userItem: String){
//calls api search
guard let url = URL(string: "https://api.nal.usda.gov/fdc/v1/foods/search?api_key=***********?query=\(userItem)") else {return}

URLSession.shared.dataTask(with: url) { (data, _,_) in
let searchResults = try! JSONDecoder().decode(APISearchResults.self, from: data!)

DispatchQueue.main.async {
for item in searchResults.foods{
self.foodDescription = item.lowercaseDescription?.firstCapitalized?? "food not valid"
self.calories = String(Double(round(item.foodNutrients[3].value!)).removeZerosFromEnd())


}

}
}
.resume()
}
}


Solución del problema

Si tiene variables adicionales que no están decodificadas, debe incluir una codingKeysenumeración con solo el JSON que necesita decodificar. Su Codificable debe ser:

struct APISearchResults: Codable {
var currentPage, totalPages: Int?
var pageList: [Int]?
//let foodSearchCriteria: FoodSearchCriteria
let foods: [Food]
enum CodingKeys: String, CodingKey {
case foods
}
}

El decodificador está buscando currentPage, totalPagesy pageListque no existen en el JSON. Cuando no incluye su propio codingKeys, el compilador los sintetiza, por lo que debe definirlos explícitamente en este caso.

No hay comentarios:

Publicar un comentario

Regla de Firestore para acceder a la generación de subcolección Permisos faltantes o insuficientes

Tengo problemas con las reglas de Firestore para permitir el acceso a algunos recursos en una subcolección. Tengo algunos requests document...