(Ceci fait suite à cette question: Utilisation du protocole Decodable avec des clés multiples .)
J'ai le code Swift suivant:
let additionalInfo = try values.nestedContainer(keyedBy: UserInfoKeys.self, forKey: .age)
age = try additionalInfo.decodeIfPresent(Int.self, forKey: .realage)
Je sais que si j'utilise decodeIfPresent
et que je n'ai pas la propriété, il la gérera toujours correctement s'il s'agit d'une variable facultative.
Par exemple, le JSON suivant fonctionne pour l’analyser à l’aide du code ci-dessus.
{
"firstname": "Test",
"lastname": "User",
"age": {"realage": 29}
}
Et le JSON suivant fonctionne également.
{
"firstname": "Test",
"lastname": "User",
"age": {"notrealage": 30}
}
Mais ce qui suit ne fonctionne pas.
{
"firstname": "Test",
"lastname": "User"
}
Comment puis-je faire fonctionner les 3 exemples? Existe-t-il quelque chose de similaire à decodeIfPresent
pour nestedContainer
?
Vous pouvez utiliser la fonction KeyedDecodingContainer
suivante:
func contains(_ key: KeyedDecodingContainer.Key) -> Bool
Retourne une valeur
Bool
indiquant si le décodeur contient une valeur associée à la clé donnée. La valeur associée à la clé donnée peut être une valeur nulle en fonction du format de données.
Par exemple, pour vérifier si la clé "age"
existe avant demandant le conteneur imbriqué correspondant:
struct Person: Decodable {
let firstName, lastName: String
let age: Int?
enum CodingKeys: String, CodingKey {
case firstName = "firstname"
case lastName = "lastname"
case age
}
enum AgeKeys: String, CodingKey {
case realAge = "realage"
case fakeAge = "fakeage"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
self.firstName = try values.decode(String.self, forKey: .firstName)
self.lastName = try values.decode(String.self, forKey: .lastName)
if values.contains(.age) {
let age = try values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age)
self.age = try age.decodeIfPresent(Int.self, forKey: .realAge)
} else {
self.age = nil
}
}
}
J'avais ce problème et j'ai trouvé cette solution, au cas où cela serait utile à quelqu'un d'autre:
let ageContainer = try? values.nestedContainer(keyedBy: AgeKeys.self, forKey: .age)
self.age = try ageContainer?.decodeIfPresent(Int.self, forKey: .realAge)
La clé est dans essayez? values.nestedContainer...
si vous avez un conteneur optionnel. C’est que vous n’avez pas besoin de vérifier si contains
est la clé.
Pouvez-vous essayer de coller votre échantillon JSON dans quicktype pour voir quels types il en déduit? Sur la base de votre question, j'ai collé vos échantillons et obtenu:
struct UserInfo: Codable {
let firstname: String
let age: Age?
let lastname: String
}
struct Age: Codable {
let realage: Int?
}
Faire en sorte que les options UserInfo.age
et Age.realage
fonctionnent, si c'est ce que vous essayez d'accomplir.