/ / swift4 descodificación de codificación para la clase modelo de análisis json anidado - json, codificación, modelo, swift4, descodificación

Descodificación de codificación swift4 para la clase de modelo de análisis json anidado - json, codificación, modelo, swift4, decodificación

Tengo una clase modelo de swift que se creó en base a una respuesta json anidada, como sigue a continuación

struct RootClass : Codable {
let details : String?
let itemCount : Int?
let list : [List]?

enum CodingKeys: String, CodingKey {
case details = "Details"
case itemCount = "ItemCount"
case list = "List"
}

init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
details = try values.decodeIfPresent(String.self, forKey: .details)
itemCount = try values.decodeIfPresent(Int.self, forKey: .itemCount)
list = try values.decodeIfPresent([List].self, forKey: .list)
}
}
struct List : Codable {

let companyID : Int?
let employeeCount : Int?
let employeeUser : EmployeeUser?

enum CodingKeys: String, CodingKey {
case companyID = "CompanyID"
case employeeCount = "EmployeeCount"
case employeeUser = "EmployeeUser"
}

init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
companyID = try values.decodeIfPresent(Int.self, forKey: .companyID)
employeeCount = try values.decodeIfPresent(Int.self, forKey: .employeeCount)
employeeUser = try EmployeeUser(from: decoder)
}
}
struct EmployeeUser : Codable {
let mobileNumber : String?
let name : String?

enum CodingKeys: String, CodingKey {
case mobileNumber = "MobileNumber"
case name = "Name"
}

init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
mobileNumber = try values.decodeIfPresent(String.self, forKey: .mobileNumber)
name = try values.decodeIfPresent(String.self, forKey: .name)
}

}

y mi respuesta es json

{
"Details": null,
"List": [
{
"CompanyID": 140,
"EmployeeUser": {
"Name": " raghu2",
"MobileNumber": "8718718710"
},
"EmployeeCount": 0
},
{
"CompanyID": 140,
"EmployeeUser": {
"Name": "new emp reg",
"MobileNumber": "1"
},
"EmployeeCount": 0
}
],
"ItemCount": 0
}

Estoy tratando de analizarlo como

guard let data = data else { return }
do {
let decoder = JSONDecoder()
let gitData = try decoder.decode(RootClass.self, from: data)
print(gitData.itemCount ?? "")
print(gitData.list![0].employeeUser?.mobileNumber ?? "")
}
catch let err {
print("Err", err)
}

Puedo obtener los valores de la clase raíz y la lista, pero obtengo valores nulos en la sección de usuario del empleado.

Respuestas

0 para la respuesta № 1

Su código de algunos problemas:

  • Todas sus llaves son opcionales. La API del proveedor le dirá qué claves están siempre presentes y cuáles son opcionales. Sigue eso.

  • decodeIfPresent fallará silenciosamente si no puede decodificar una clave. Al depurar su aplicación, quiere que las cosas falle con una explosión para que pueda corregir el error antes de pasar a producción.

  • Usted escribió mucho más código del necesario. Todos aquellos init(from decoder: ) Las funciones no son necesarias. Uno causó tu problema

Su problema fue causado por esta línea:

struct List : Codable {
init(from decoder: Decoder) throws {
...
employeeUser = try EmployeeUser(from: decoder)
}
}

Le estás pidiendo a Swift que decodifique al mismo JSON a un List y un EmployeeUser objeto. Obviamente, eso no es válido. Pero cuando decodifiques list Dentro de RootClass, tu llamas decodeIfPresent:

// In Rootclass
list = try values.decodeIfPresent([List].self, forKey: .list)

¡Esta llamada falló silenciosamente y nunca supiste cuál era el problema!


Solución

Cambia cómo inicializas employeeUser a esto:

employeeUser = try values.decodeIfPresent(EmployeeUser.self, forKey: .employeeUser)

Pero la solución más elegante es eliminar todos aquellos. init(from decoder: ). El compilador los sintetizará por ti.

Y por último, arregla esos opcionales!