estoy analizando esta API con Swift Codable
"total": 7, "searchResult": [ null, { "name": "joe" "family": "adam" }, null, { "name": "martin" "family": "lavrix" }, { "name": "sarah" "family": "mia" }, null, { "name": "ali" "family": "abraham" } ] con este modelo de PaginationModel :
class PaginationModel<T: Codable>: Codable { var total: Int? var data: T? enum CodingKeys: String, CodingKey { case total case data = "searchResult" } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.total = try container.decodeIfPresent(Int.self, forKey: .total) self.data = try container.decodeIfPresent(T.self, forKey: .data) } } y modelo User :
struct User: Codable { var name: String? var family: String? } Llamo a jsonDecoder así para analizar API json:
let responseObject = try JSONDecoder().decode(PaginationModel<[User?]>.self, from: json) ahora mi problema es null en searchResult Array. se analizó correctamente y cuando accedí a data en paginationModel encontré null en la matriz.
¿Cómo puedo ignorar todos null al analizar la API y el resultado será una matriz sin ningún null
En primer lugar, recomendaría considerar siempre que PaginationModel se compone de matrices. No tiene que pasar [User] como tipo genérico, simplemente puede pasar User . Luego, el analizador puede usar el conocimiento de que analiza matrices y maneja null automáticamente:
class PaginationModel<T: Codable>: Codable { var total: Int? var data: [T]? enum CodingKeys: String, CodingKey { case total case data = "searchResult" } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.total = try container.decodeIfPresent(Int.self, forKey: .total) self.data = (try container.decodeIfPresent([T?].self, forKey: .data))?.compactMap { $0 } } }Es posible que desee eliminar los opcionales aquí y usar algunos valores predeterminados en su lugar:
class PaginationModel<T: Codable>: Codable { var total: Int = 0 var data: [T] = [] enum CodingKeys: String, CodingKey { case total case data = "searchResult" } required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.total = (try container.decodeIfPresent(Int.self, forKey: .total)) ?? 0 self.data = ((try container.decodeIfPresent([T?].self, forKey: .data)) ?? []).compactMap { $0 } } }Solución simple, filtrar data después de decodificar
let responseObject = try JSONDecoder().decode(PaginationModel<[User?]>.self, from: data) responseObject.data = responseObject.data?.filter{$0 != nil}Puede agregar una verificación de tipo de matriz dentro de decode:
required init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.total = try container.decodeIfPresent(Int.self, forKey: .total) self.data = try container.decodeIfPresent(T.self, forKey: .data) //add the following: if let array = self.data as? Array<Any?> { self.data = ( array.compactMap{$0} as? T) } }