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 № 1Su 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!