es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Decodificación de Swift Json con datos entrantes inciertos

Estoy teniendo dificultades para decodificar algunos datos Json en Swift.

Mi API de backend me devolverá un array de X o un objeto con (al menos) una propiedad llamada “items” de tipo array de X.

He buscado pero no he encontrado soluciones. ¿Tienes alguna?

struct A: Decodable {
   var items: [X]
   // algunas otras propiedades opcionales

public init(from decoder: Decoder) throws {
       // A veces recibo el objeto A correcto
       // A veces solo recibo el array de X sin el objeto envolvente de tipo A.
   }
}
<code>
Y para empeorar las cosas, estoy obligado a decodificar como si siempre estuviera recibiendo un objeto de tipo A... :
</code>
myObjectOfTypeA = try decoder.decode(A.self, from: data)

La mayoría de las veces, recibiré un objeto A adecuado como este:

{
"items":
[
{
"id": 7,
"startsOn": "2021-03-01",
"endsOn": "2021-12-31"
},
{
"id": 6,
"startsOn": "2021-04-19",
"endsOn": "2022-04-04"
}
],
"next": null,
"prev": null,
"count": 2
}

Pero a veces, solo recibiré el array de items así:

[
{
"id": 7,
"startsOn": "2021-03-01",
"endsOn": "2021-12-31"
},
{
"id": 6,
"startsOn": "2021-04-19",
"endsOn": "2022-04-04"
}
]

Cualquier idea sería muy apreciada porque claramente estoy sin ideas… 😃

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Una posible solución es crear dos estructuras separadas para decodificar los datos de respuesta, una para decodificar el objeto con la propiedad “items” y otra para decodificar solo el array “items”.

    Por ejemplo, podrías tener una estructura como esta para decodificar el objeto:

    struct ResponseObject: Decodable {
       var items: [X]
       // otras propiedades
    
       public init(from decoder: Decoder) throws {
           let container = try decoder.container(keyedBy: CodingKeys.self)
           items = try container.decode([X].self, forKey: .items)
           // decodificar otras propiedades si es necesario
       }
    
       private enum CodingKeys: String, CodingKey {
           case items
           // otras claves de codificación para otras propiedades
       }
    }
    

    Y otra estructura como esta para decodificar solo el array:

    struct ResponseArray: Decodable {
       var items: [X]
    
       public init(from decoder: Decoder) throws {
           // Solo decodificar el array de items
           items = try decoder.decode([X].self)
       }
    }
    

    Luego, puedes intentar decodificar los datos de respuesta como un objeto primero y, si eso falla, intentar decodificarlo como un array:

    do {
       myObjectOfTypeA = try decoder.decode(ResponseObject.self, from: data)
    } catch {
       // No se pudo decodificar como un objeto, intentar decodificar como un array
       let arrayResponse = try decoder.decode(ResponseArray.self, from: data)
       myObjectOfTypeA.items = arrayResponse.items
    }
    

    De esta manera, puedes manejar ambos casos en los que recibes un objeto con la propiedad “items” y solo el array “items” sin que tu aplicación se bloquee.

Comments are closed.