Voici des implémentations simples de DictionaryEncoder/ DictionaryDecoderqui enveloppent JSONEncoder, JSONDecoderet JSONSerialization, qui gèrent également les stratégies d'encodage / décodage ...
Merci beaucoup!, L'alternative serait d'utiliser l'héritage mais le site appelant ne pourrait pas déduire le type comme un dictionnaire car il y aurait 2 fonctions de types de retour différents.
user1046037
17
J'ai créé une bibliothèque appelée CodableFirebase et son objectif initial était de l'utiliser avec Firebase Database, mais elle fait en fait ce dont vous avez besoin: elle crée un dictionnaire ou tout autre type comme dans JSONDecodermais vous n'avez pas besoin de faire la double conversion ici comme vous le faites dans d'autres réponses. Cela ressemblerait donc à quelque chose comme:
importCodableFirebaselet model =Foo(a:1, b:2)let dict =try!FirebaseEncoder().encode(model)
Il n'y a aucun moyen intégré de le faire. Comme indiqué ci - dessus, si vous n'avez aucun problème de performances, vous pouvez accepter l' implémentation JSONEncoder+ JSONSerialization.
Mais je préférerais suivre la voie de la bibliothèque standard pour fournir un objet encodeur / décodeur.
classDictionaryEncoder{privatelet jsonEncoder =JSONEncoder()/// Encodes given Encodable value into an array or dictionary
func encode<T>(_ value: T)throws->Anywhere T:Encodable{let jsonData =try jsonEncoder.encode(value)returntryJSONSerialization.jsonObject(with: jsonData, options:.allowFragments)}}classDictionaryDecoder{privatelet jsonDecoder =JSONDecoder()/// Decodes given Decodable type from given array or dictionary
func decode<T>(_ type: T.Type, from json:Any)throws-> T where T:Decodable{let jsonData =tryJSONSerialization.data(withJSONObject: json, options:[])returntry jsonDecoder.decode(type, from: jsonData)}}
Je pense vraiment qu'il y a une valeur à pouvoir simplement utiliser Codablepour encoder vers / à partir de dictionnaires, sans jamais avoir l'intention de frapper JSON / Plists / quoi que ce soit. Il existe de nombreuses API qui vous donnent simplement un dictionnaire ou attendent un dictionnaire, et il est agréable de pouvoir les échanger facilement avec des structures ou des objets Swift, sans avoir à écrire un code standard sans fin.
J'ai joué avec du code basé sur la source Foundation JSONEncoder.swift (qui implémente en fait l'encodage / décodage du dictionnaire en interne, mais ne l'exporte pas).
C'est encore assez approximatif, mais je l'ai développé un peu pour que, par exemple, il puisse remplir les valeurs manquantes avec des valeurs par défaut lors du décodage.
J'ai modifié PropertyListEncoder du projet Swift en DictionaryEncoder, simplement en supprimant la sérialisation finale du dictionnaire au format binaire. Vous pouvez faire la même chose vous-même, ou vous pouvez prendre mon code de ici
J'ai écrit un rapide essentiel pour gérer ce (ne pas utiliser le protocole codable). Attention, il ne vérifie pas le type de valeurs et ne fonctionne pas de manière récursive sur les valeurs encodables.
classDictionaryEncoder{var result:[String:Any]init(){
result =[:]}func encode(_ encodable:DictionaryEncodable)->[String:Any]{
encodable.encode(self)return result
}func encode<T, K>(_ value: T, key: K)where K:RawRepresentable, K.RawValue==String{
result[key.rawValue]= value
}}protocolDictionaryEncodable{func encode(_ encoder:DictionaryEncoder)}
Il n'y a pas de moyen simple de faire cela dans Codable. Vous devez implémenter le protocole Encodable / Decodable pour votre structure. Pour votre exemple, vous devrez peut-être écrire comme ci-dessous
À bien y penser, la question n'a pas de réponse dans le cas général, car l' Encodableinstance peut être quelque chose de non sérialisable dans un dictionnaire, tel qu'un tableau:
let payload =[1,2,3]let encoded =tryJSONEncoder().encode(payload)//"[1,2,3]"
Je dois admettre que je ne comprends toujours pas pourquoi ce vote est défavorable :–) La mise en garde n'est-elle pas vraie? Ou le cadre n'est pas utile?
Réponses:
Si cela ne vous dérange pas de déplacer un peu les données, vous pouvez utiliser quelque chose comme ceci:
Ou une variante optionnelle
En supposant qu'il
Foo
est conformeCodable
ou vraiment,Encodable
vous pouvez le faire.Si vous voulez aller dans l'autre sens (
init(any)
), jetez un œil à ce Init un objet conforme à Codable avec un dictionnaire / tableaula source
Voici des implémentations simples de
DictionaryEncoder
/DictionaryDecoder
qui enveloppentJSONEncoder
,JSONDecoder
etJSONSerialization
, qui gèrent également les stratégies d'encodage / décodage ...L'utilisation est similaire à
JSONEncoder
/JSONDecoder
…et
Pour plus de commodité, j'ai mis tout cela dans un dépôt… https://github.com/ashleymills/SwiftDictionaryCoding
la source
J'ai créé une bibliothèque appelée CodableFirebase et son objectif initial était de l'utiliser avec Firebase Database, mais elle fait en fait ce dont vous avez besoin: elle crée un dictionnaire ou tout autre type comme dans
JSONDecoder
mais vous n'avez pas besoin de faire la double conversion ici comme vous le faites dans d'autres réponses. Cela ressemblerait donc à quelque chose comme:la source
Je ne sais pas si c'est le meilleur moyen, mais vous pouvez certainement faire quelque chose comme:
la source
let dict = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(struct), options: []) as? [String: Any]
la source
Il n'y a aucun moyen intégré de le faire. Comme indiqué ci - dessus, si vous n'avez aucun problème de performances, vous pouvez accepter l' implémentation
JSONEncoder
+JSONSerialization
.Mais je préférerais suivre la voie de la bibliothèque standard pour fournir un objet encodeur / décodeur.
Vous pouvez l'essayer avec le code suivant:
J'essaye de force ici de raccourcir l'exemple. Dans le code de production, vous devez gérer les erreurs de manière appropriée.
la source
Dans certains projets, j'utilise la réflexion rapide. Mais attention, les objets codables imbriqués, ne sont pas mappés là aussi.
la source
Je pense vraiment qu'il y a une valeur à pouvoir simplement utiliser
Codable
pour encoder vers / à partir de dictionnaires, sans jamais avoir l'intention de frapper JSON / Plists / quoi que ce soit. Il existe de nombreuses API qui vous donnent simplement un dictionnaire ou attendent un dictionnaire, et il est agréable de pouvoir les échanger facilement avec des structures ou des objets Swift, sans avoir à écrire un code standard sans fin.J'ai joué avec du code basé sur la source Foundation JSONEncoder.swift (qui implémente en fait l'encodage / décodage du dictionnaire en interne, mais ne l'exporte pas).
Le code peut être trouvé ici: https://github.com/elegantchaos/DictionaryCoding
C'est encore assez approximatif, mais je l'ai développé un peu pour que, par exemple, il puisse remplir les valeurs manquantes avec des valeurs par défaut lors du décodage.
la source
J'ai modifié PropertyListEncoder du projet Swift en DictionaryEncoder, simplement en supprimant la sérialisation finale du dictionnaire au format binaire. Vous pouvez faire la même chose vous-même, ou vous pouvez prendre mon code de ici
Il peut être utilisé comme ceci:
la source
J'ai écrit un rapide essentiel pour gérer ce (ne pas utiliser le protocole codable). Attention, il ne vérifie pas le type de valeurs et ne fonctionne pas de manière récursive sur les valeurs encodables.
la source
Il n'y a pas de moyen simple de faire cela dans Codable. Vous devez implémenter le protocole Encodable / Decodable pour votre structure. Pour votre exemple, vous devrez peut-être écrire comme ci-dessous
la source
J'ai créé un pod ici https://github.com/levantAJ/AnyCodable pour faciliter le décodage et l' encodage
[String: Any]
et[Any]
Et vous pouvez décoder et encoder
[String: Any]
et[Any]
la source
Si vous utilisez SwiftyJSON , vous pouvez faire quelque chose comme ceci:
JSON(data: JSONEncoder().encode(foo)).dictionaryObject
la source
Voici une solution basée sur un protocole:
Et voici comment l'utiliser:
la source
Voici le dictionnaire -> objet. Swift 5.
la source
À bien y penser, la question n'a pas de réponse dans le cas général, car l'
Encodable
instance peut être quelque chose de non sérialisable dans un dictionnaire, tel qu'un tableau:En dehors de cela, j'ai écrit quelque chose de similaire en tant que cadre .
la source