Comment décoder un imbriquée struct JSON avec Swift Décodable protocole?
Voici mon JSON
{
"id": 1,
"user": {
"user_name": "Tester",
"real_info": {
"full_name":"Jon Doe"
}
},
"reviews_count": [
{
"count": 4
}
]
}
Voici la structure que je veux sauvegardé (incomplet)
struct ServerResponse: Decodable {
var id: String
var username: String
var fullName: String
var reviewCount: Int
enum CodingKeys: String, CodingKey {
case id,
//How do i get nested values?
}
}
J'ai regardé La Documentation d'Apple sur le décodage des structures imbriquées, mais je ne comprends toujours pas comment faire les différents niveaux de l'JSON correctement. Toute aide sera très appréciée.
Vous devez vous connecter pour publier un commentaire.
Une autre approche consiste à créer un modèle intermédiaire qui correspond au format JSON (avec l'aide d'un outil comme quicktype.io), laissez Swift générer les méthodes pour le décoder, puis de ramasser les morceaux que vous voulez dans la version finale du modèle de données:
Cela vous permet également de facilement parcourir
reviews_count
, devrait-il contenir plus de 1 la valeur à l'avenir.Encodable
pour laServerResponse
structure suivant la même approche. Est-il même possible?ServerResponse
a moins de données queRawServerResponse
. Vous pouvez capturer l'RawServerResponse
exemple, de la mettre à jour les propriétés deServerResponse
, puis de générer du JSON à partir de cela. Vous pouvez obtenir la meilleure aide en publiant une nouvelle question avec le problème auquel vous êtes confronté.Afin de résoudre votre problème, vous pouvez diviser votre
RawServerResponse
mise en œuvre en plusieurs logique de pièces (à l'aide de Swift 5).#1. Mettre en œuvre les propriétés et nécessaire clés de codage
#2. Définir la stratégie de décodage pour
id
propriété#3. Définir la stratégie de décodage pour
userName
propriété#4. Définir la stratégie de décodage pour
fullName
propriété#5. Définir la stratégie de décodage pour
reviewCount
propriétéMise en œuvre complète
Utilisation
struct
vous avez utiliséenum
avec les touches. ce qui est beaucoup plus élégantPlutôt que d'avoir un gros
CodingKeys
énumération avec tous les touches que vous aurez besoin pour le décodage JSON, je vous conseille de fractionnement les clés pour chaque de votre imbriquée objets JSON, utilisant des énumérations pour préserver la hiérarchie:Ce sera plus facile de garder une trace des clés à chaque niveau dans votre JSON.
Maintenant, en gardant à l'esprit que:
Un incrustée conteneur est utilisée pour décoder un objet JSON, et est décodé avec un
CodingKey
conformes type (tels que ceux que nous avons définis ci-dessus).Un unkeyed conteneur est utilisée pour décoder un tableau JSON, et est décodé séquentiellement (j'.e chaque fois que vous appelez une décoder ou conteneur imbriqué méthode, il avance vers le prochain élément dans le tableau). Voir la deuxième partie de la réponse pour savoir comment vous pouvez parcourir une.
Après l'obtention de votre haut niveau incrustée conteneur à partir du décodeur avec
conteneur(keyedBy:)
(que vous avez un objet JSON dans le haut-niveau), vous pouvez utiliser plusieurs fois les méthodes:nestedContainer(keyedBy:forKey:)
pour obtenir un objet imbriqué à partir d'un objet pour une clé donnéenestedUnkeyedContainer(forKey:)
pour obtenir un tableau imbriqué à partir d'un objet pour une clé donnéenestedContainer(keyedBy:)
pour obtenir le prochain objet imbriqué à partir d'un tableaunestedUnkeyedContainer()
pour obtenir le prochain tableau imbriqué à partir d'un tableauPar exemple:
Exemple de décodage:
Une itération à travers un unkeyed conteneur
Considérant le cas où vous souhaitez
reviewCount
être un[Int]
, où chaque élément représente la valeur de l'"count"
clé dans le imbriqués JSON:Vous aurez besoin pour itérer sur les imbriquée unkeyed conteneur, l'obtention de la imbriquée à clé contenant à chaque itération, et le décodage de la valeur pour l'
"count"
clé. Vous pouvez utiliser lecount
propriété de la unkeyed conteneur afin de pré-allouer la résultante de tableau, puis laisAtEnd
propriété d'itérer à travers elle.Par exemple:
I would advise splitting the keys for each of your nested JSON objects up into multiple nested enumerations, thereby making it easier to keep track of the keys at each level in your JSON
?CodingKeys
enum avec tous les clés dont vous aurez besoin pour décoder votre objet JSON, vous devez les diviser en plusieurs énumérations pour chaque objet JSON – par exemple, dans le code ci-dessus, nous avonsCodingKeys.User
avec les clés pour décoder l'utilisateur de l'objet JSON ({ "user_name": "Tester", "real_info": { "full_name": "Jon Doe" } }
), donc juste les clés pour"user_name"
&"real_info"
.reviews_count
qui est un tableau de dictionnaire. Actuellement, le code fonctionne comme prévu. Mon reviewsCount ne présente qu'une valeur dans le tableau. Mais si je voulais un tableau de review_count, alors j'avais besoin de simplement déclarervar reviewCount: Int
comme un tableau de droite? ->var reviewCount: [Int]
. Et puis j'avais besoin de modifier également laReviewsCount
enum droit?Int
, mais un tableau d'objets JSON qui ont chacun uneInt
valeur pour une clé donnée – ce que vous auriez besoin de faire est de parcourir la unkeyed conteneur et obtenir tous les imbriquée à clé conteneurs, décodage deInt
pour chacun (et en ajoutant ceux de votre tableau), l'e.g gist.github.com/hamishknight/9b5c202fe6d8289ee2cb9403876a1b41Beaucoup de bonnes réponses ont déjà été posté, mais il y a une méthode plus simple de ne pas décrit encore l'OMI.
Lorsque le champ JSON noms sont écrits à l'aide
snake_case_notation
vous pouvez toujours utiliser lecamelCaseNotation
dans votre Swift fichier.Il vous suffit de définir
Après cette ☝️ ligne Swift sera automatiquement correspondre à tous les
snake_case
champs du JSON à lacamelCase
champs de la Swift modèle.E. g.
Voici le code complet
1. L'écriture du Modèle
2. Réglage du Décodeur
3. Décodage
Vous pouvez également utiliser la bibliothèque KeyedCodable j'ai préparé. Il aura besoin de moins de code. Laissez-moi savoir ce que vous en pensez.