J'analyse cette API avec Swift Codable
let responseObject = try JSONDecoder().decode(PaginationModel<[User?]>.self, from: json)
avec ce PaginationModel
:
struct User: Codable { var name: String? var family: String? }
et User
Model:
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) } }
j'appelle jsonDecoder
comme ceci pour analyser l'API json:
"total": 7, "searchResult": [ null, { "name": "joe" "family": "adam" }, null, { "name": "martin" "family": "lavrix" }, { "name": "sarah" "family": "mia" }, null, { "name": "ali" "family": "abraham" } ]
maintenant mon problème est null
dans searchResult
Array. il a été analysé correctement et quand j'accède aux données
dans paginationModel
j'ai trouvé null
dans le tableau.
comment puis-je tout ignorer null
lors de l'analyse de l'API, et le résultat sera un tableau sans null
3 Réponses :
Solution simple, filtrez les données
après décodage
let responseObject = try JSONDecoder().decode(PaginationModel<[User?]>.self, from: data) responseObject.data = responseObject.data?.filter{$0 != nil}
cela peut être une solution, mais je recherche une meilleure solution. surtout tout ce qui doit être fait dans PaginationModel
Le problème est que le T
générique peut être un objet unique aussi bien qu'un tableau. La meilleure solution est de filtrer les valeurs null
déjà présentes sur le serveur.
@Sajjad, PaginationModel
n'a actuellement pas assez d'informations sur le type réel utilisé dans le générique, vous devrez transmettre les informations que vous recherchez réellement Array
, puis dans < code> init (du décodeur: Decoder) décode-le d'abord comme [T?]
, puis compactMap
en [T]
et enregistrer dans la propriété.
D'accord. si je change data: T?
en data: [T?]
, puis-je le gérer?
Vous pouvez ajouter une vérification de type de tableau dans le décodage:
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) } }
En premier lieu, je conseillerais de toujours considérer que PaginationModel
est composé de tableaux. Il n'est pas nécessaire de passer [User]
comme type générique, vous pouvez simplement passer User
. Ensuite, l'analyseur peut utiliser la connaissance qu'il analyse les tableaux et gère null
automatiquement:
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 } } }
Vous pouvez supprimer les options ici et utiliser des valeurs par défaut à la place: p>
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 } } }
Je recommanderais également de rendre le total (probable) et les données (certainement) obligatoires plutôt que facultatifs. Cela simplifiera beaucoup cela en se débarrassant de decodeIfPresent. (De même, le nom et la famille sont-ils vraiment facultatifs? Y a-t-il une différence entre une chaîne "manquante" et une chaîne vide?)
@RobNapier Très vrai.
c'est exactement ce que je veux. tnx @Sulthan
@RobNapier je suis d'accord avec vous. mais notre développeur côté serveur a dit que s'ils venaient soudainement avec une valeur nulle (à cause de bogues du serveur ou ...), vous devez le gérer
Même dans ce cas, vous feriez mieux de les rendre obligatoires et de les définir par défaut sur des chaînes vides dans le décodeur afin de ne pas avoir à les traiter comme facultatives partout dans le programme.
quelle est la meilleure pratique pour cela? pouvez-vous écrire du code? S'il vous plaît
@Sajjad Mis à jour.
@ user28434 j'ai mis à jour ma question
oui avec ça?, il est normalement analysé à null. je veux un tableau sans objet nul