Aquí hay implementaciones simples de DictionaryEncoder/ DictionaryDecoderque envuelven JSONEncoder, JSONDecodery JSONSerializationque también manejan estrategias de codificación / decodificación ...
¡Muchas gracias!, La alternativa sería usar la herencia, pero el sitio de llamada no podría inferir el tipo como un diccionario, ya que habría 2 funciones de diferentes tipos de retorno.
user1046037
17
Creé una biblioteca llamada CodableFirebase y su propósito inicial era usarla con Firebase Database, pero en realidad hace lo que necesita: crea un diccionario o cualquier otro tipo como en, JSONDecoderpero no necesita hacer la doble conversión aquí. como lo hace en otras respuestas. Entonces se vería algo como:
importCodableFirebaselet model =Foo(a:1, b:2)let dict =try!FirebaseEncoder().encode(model)
Esto solo funcionaría para estructuras con todas las propiedades del mismo tipo
Leo Dabus
1
Intenté "let dict = try JSONDecoder (). Decode ([String: Int] .self, from: JSONEncoder (). Encode (foo))" y obtuve "Se esperaba que decodificara Dictionary <String, Any> pero encontré un matriz en su lugar ". podría ayudar por favor
No hay una forma incorporada de hacer eso. Como se respondió anteriormente, si no tiene problemas de rendimiento, puede aceptar la implementación JSONEncoder+ JSONSerialization.
Pero prefiero seguir el camino de la biblioteca estándar para proporcionar un objeto codificador / decodificador.
classDictionaryEncoder{privatelet jsonEncoder =JSONEncoder()/// Encodes given Encodable value into an array or dictionaryfunc 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 dictionaryfunc 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)}}
Definitivamente creo que hay algo de valor en poder usar Codablepara codificar hacia / desde diccionarios, sin la intención de llegar a JSON / Plists / lo que sea. Hay muchas API que simplemente le devuelven un diccionario, o esperan un diccionario, y es bueno poder intercambiarlas fácilmente con estructuras u objetos Swift, sin tener que escribir un código repetitivo interminable.
He estado jugando con un código basado en la fuente Foundation JSONEncoder.swift (que en realidad implementa la codificación / decodificación del diccionario internamente, pero no lo exporta).
Todavía es bastante tosco, pero lo he ampliado un poco para que, por ejemplo, pueda completar los valores faltantes con valores predeterminados al decodificar.
He modificado PropertyListEncoder del proyecto Swift en un DictionaryEncoder, simplemente eliminando la serialización final del diccionario en formato binario. Puede hacer lo mismo usted mismo, o puede tomar mi código desde aquí
Escribí una breve descripción para manejar esto (sin usar el protocolo codificable). Tenga cuidado, no verifica ningún valor y no funciona de forma recursiva en valores que son codificables.
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)}
No hay una forma sencilla de hacer esto en Codable. Debe implementar el protocolo codificable / decodificable para su estructura. Para su ejemplo, es posible que deba escribir lo siguiente
Ahora que lo pienso, la pregunta no tiene respuesta en el caso general, ya que la Encodableinstancia puede ser algo no serializable en un diccionario, como una matriz:
let payload =[1,2,3]let encoded =tryJSONEncoder().encode(payload)//"[1,2,3]"
Respuestas:
Si no le importa un poco de cambio de datos, puede usar algo como esto:
O una variante opcional
Suponiendo que se
Foo
ajusteCodable
o realmenteEncodable
entonces puede hacer esto.Si desea ir al revés (
init(any)
), eche un vistazo a este Init an object conforme a Codable con un diccionario / matrizfuente
Aquí hay implementaciones simples de
DictionaryEncoder
/DictionaryDecoder
que envuelvenJSONEncoder
,JSONDecoder
yJSONSerialization
que también manejan estrategias de codificación / decodificación ...El uso es similar a
JSONEncoder
/JSONDecoder
…y
Para mayor comodidad, he puesto todo esto en un repositorio ... https://github.com/ashleymills/SwiftDictionaryCoding
fuente
Creé una biblioteca llamada CodableFirebase y su propósito inicial era usarla con Firebase Database, pero en realidad hace lo que necesita: crea un diccionario o cualquier otro tipo como en,
JSONDecoder
pero no necesita hacer la doble conversión aquí. como lo hace en otras respuestas. Entonces se vería algo como:fuente
No estoy seguro de si es la mejor manera, pero definitivamente puedes hacer algo como:
fuente
let dict = try JSONSerialization.jsonObject(with: try JSONEncoder().encode(struct), options: []) as? [String: Any]
fuente
No hay una forma incorporada de hacer eso. Como se respondió anteriormente, si no tiene problemas de rendimiento, puede aceptar la implementación
JSONEncoder
+JSONSerialization
.Pero prefiero seguir el camino de la biblioteca estándar para proporcionar un objeto codificador / decodificador.
Puedes probarlo con el siguiente código:
Estoy intentando forzar aquí acortar el ejemplo. En el código de producción, debe manejar los errores de manera adecuada.
fuente
En algún proyecto, utilizo la reflexión rápida. Pero tenga cuidado, los objetos codificables anidados no están mapeados allí también.
fuente
Definitivamente creo que hay algo de valor en poder usar
Codable
para codificar hacia / desde diccionarios, sin la intención de llegar a JSON / Plists / lo que sea. Hay muchas API que simplemente le devuelven un diccionario, o esperan un diccionario, y es bueno poder intercambiarlas fácilmente con estructuras u objetos Swift, sin tener que escribir un código repetitivo interminable.He estado jugando con un código basado en la fuente Foundation JSONEncoder.swift (que en realidad implementa la codificación / decodificación del diccionario internamente, pero no lo exporta).
El código se puede encontrar aquí: https://github.com/elegantchaos/DictionaryCoding
Todavía es bastante tosco, pero lo he ampliado un poco para que, por ejemplo, pueda completar los valores faltantes con valores predeterminados al decodificar.
fuente
He modificado PropertyListEncoder del proyecto Swift en un DictionaryEncoder, simplemente eliminando la serialización final del diccionario en formato binario. Puede hacer lo mismo usted mismo, o puede tomar mi código desde aquí
Se puede usar así:
fuente
Escribí una breve descripción para manejar esto (sin usar el protocolo codificable). Tenga cuidado, no verifica ningún valor y no funciona de forma recursiva en valores que son codificables.
fuente
No hay una forma sencilla de hacer esto en Codable. Debe implementar el protocolo codificable / decodificable para su estructura. Para su ejemplo, es posible que deba escribir lo siguiente
fuente
He creado un pod aquí https://github.com/levantAJ/AnyCodable para facilitar la decodificación y codificación
[String: Any]
y[Any]
Y puedes decodificar y codificar
[String: Any]
y[Any]
fuente
Si está utilizando SwiftyJSON , podría hacer algo como esto:
JSON(data: JSONEncoder().encode(foo)).dictionaryObject
fuente
Aquí hay una solución basada en protocolo:
Y así es como se usa:
fuente
Aquí está el diccionario -> objeto. Rápido 5.
fuente
Ahora que lo pienso, la pregunta no tiene respuesta en el caso general, ya que la
Encodable
instancia puede ser algo no serializable en un diccionario, como una matriz:Aparte de eso, he escrito algo similar como marco .
fuente