ser recomendable que puedo personas para mas libros leer lecturas inteligentes inteligente faciles empezar deberia culturizarse json swift swift4 codable

json - puedo - que libros es recomendable leer para ser mas inteligente



Swift 4 JSON La forma más fácil de decodificar para decodificar el cambio de tipo (6)

Con el protocolo Codable de swift4, hay un gran nivel de estrategias de conversión de datos y datos bajo el capó.

Dado el JSON:

{ "name": "Bob", "age": 25, "tax_rate": "4.25" }

Quiero coaccionarlo en la siguiente estructura.

struct ExampleJson: Decodable { var name: String var age: Int var taxRate: Float enum CodingKeys: String, CodingKey { case name, age case taxRate = "tax_rate" } }

La estrategia de decodificación de fecha puede convertir una fecha basada en cadena en una fecha.

¿Hay algo que hace eso con un flotador basado en cadenas?

De lo contrario, me quedé atascado con el uso de CodingKey para ingresar una cadena y usar un objeto informático:

enum CodingKeys: String, CodingKey { case name, age case sTaxRate = "tax_rate" } var sTaxRate: String var taxRate: Float { return Float(sTaxRate) ?? 0.0 }

Este tipo de hilos me hacen más mantenimiento del que parece que debería ser necesario.

¿Es esta la forma más sencilla o hay algo similar a DateDecodingStrategy para otras conversiones de tipos?

Actualización : Debo tener en cuenta: También he ido por la ruta de anulación

init(from decoder:Decoder)

Pero eso es en la dirección opuesta, ya que me obliga a hacerlo todo por mí mismo.


De acuerdo con sus necesidades, puede elegir una de las dos formas siguientes para resolver su problema.

# 1. Usando Decodable init(from:) initializer

Use esta estrategia cuando necesite convertir de String a Float para una sola estructura, enumeración o clase.

import Foundation struct ExampleJson: Decodable { var name: String var age: Int var taxRate: Float enum CodingKeys: String, CodingKey { case name, age, taxRate = "tax_rate" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) name = try container.decode(String.self, forKey: CodingKeys.name) age = try container.decode(Int.self, forKey: CodingKeys.age) let taxRateString = try container.decode(String.self, forKey: CodingKeys.taxRate) guard let taxRateFloat = Float(taxRateString) else { let context = DecodingError.Context(codingPath: container.codingPath + [CodingKeys.taxRate], debugDescription: "Could not parse json key to a Float object") throw DecodingError.dataCorrupted(context) } taxRate = taxRateFloat } }

Uso:

import Foundation let jsonString = """ { "name": "Bob", "age": 25, "tax_rate": "4.25" } """ let data = jsonString.data(using: String.Encoding.utf8)! let decoder = JSONDecoder() let exampleJson = try! decoder.decode(ExampleJson.self, from: data) dump(exampleJson) /* prints: ▿ __lldb_expr_126.ExampleJson - name: "Bob" - age: 25 - taxRate: 4.25 */

# 2. Usando un modelo intermedio

Use esta estrategia cuando tenga muchas claves anidadas en su JSON o cuando necesite convertir muchas claves (por ejemplo, de String a Float ) de su JSON.

import Foundation fileprivate struct PrivateExampleJson: Decodable { var name: String var age: Int var taxRate: String enum CodingKeys: String, CodingKey { case name, age, taxRate = "tax_rate" } } struct ExampleJson: Decodable { var name: String var age: Int var taxRate: Float init(from decoder: Decoder) throws { let privateExampleJson = try PrivateExampleJson(from: decoder) name = privateExampleJson.name age = privateExampleJson.age guard let convertedTaxRate = Float(privateExampleJson.taxRate) else { let context = DecodingError.Context(codingPath: [], debugDescription: "Could not parse json key to a Float object") throw DecodingError.dataCorrupted(context) } taxRate = convertedTaxRate } }

Uso:

import Foundation let jsonString = """ { "name": "Bob", "age": 25, "tax_rate": "4.25" } """ let data = jsonString.data(using: String.Encoding.utf8)! let decoder = JSONDecoder() let exampleJson = try! decoder.decode(ExampleJson.self, from: data) dump(exampleJson) /* prints: ▿ __lldb_expr_126.ExampleJson - name: "Bob" - age: 25 - taxRate: 4.25 */


Desafortunadamente, no creo que exista tal opción en la API de JSONDecoder actual. Solo existe una opción para convertir valores de punto flotante excepcionales hacia y desde una representación de cadena.

Otra posible solución para decodificar manualmente es definir un tipo de envoltorio Codable para cualquier LosslessStringConvertible que pueda codificar y decodificar desde su representación de String :

struct StringCodableMap<Decoded : LosslessStringConvertible> : Codable { var decoded: Decoded init(_ decoded: Decoded) { self.decoded = decoded } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let decodedString = try container.decode(String.self) guard let decoded = Decoded(decodedString) else { throw DecodingError.dataCorruptedError( in: container, debugDescription: """ The string /(decodedString) is not representable as a /(Decoded.self) """ ) } self.decoded = decoded } func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(decoded.description) } }

Entonces puede tener una propiedad de este tipo y usar la conformidad Codable generada Codable :

struct Example : Codable { var name: String var age: Int var taxRate: StringCodableMap<Float> private enum CodingKeys: String, CodingKey { case name, age case taxRate = "tax_rate" } }

Aunque desafortunadamente, ahora tiene que hablar en términos de taxRate.decoded para interactuar con el valor Float .

Sin embargo, siempre se podría definir una propiedad computada de reenvío simple para aliviar esto:

struct Example : Codable { var name: String var age: Int private var _taxRate: StringCodableMap<Float> var taxRate: Float { get { return _taxRate.decoded } set { _taxRate.decoded = newValue } } private enum CodingKeys: String, CodingKey { case name, age case _taxRate = "tax_rate" } }

Aunque esto todavía no es tan simple como debería ser, con suerte, una versión posterior de la API JSONDecoder incluirá más opciones de decodificación personalizadas, o bien tendrá la capacidad de expresar conversiones de tipos dentro de la API Codable .

Sin embargo, una de las ventajas de crear el tipo de envoltorio es que también se puede utilizar para simplificar la descodificación y la codificación manual. Por ejemplo, con decodificación manual:

struct Example : Decodable { var name: String var age: Int var taxRate: Float private enum CodingKeys: String, CodingKey { case name, age case taxRate = "tax_rate" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.name = try container.decode(String.self, forKey: .name) self.age = try container.decode(Int.self, forKey: .age) self.taxRate = try container.decode(StringCodableMap<Float>.self, forKey: .taxRate).decoded } }


Puedes usar la lazy var para convertir la propiedad a otro tipo:

struct ExampleJson: Decodable { var name: String var age: Int lazy var taxRate: Float = { Float(self.tax_rate)! }() private var tax_rate: String }

Una desventaja de este enfoque es que no puede definir una constante de let si desea acceder a taxRate , ya que la primera vez que accede a ella, está mutando la estructura.

// Cannot use `let` here var example = try! JSONDecoder().decode(ExampleJson.self, from: data)


Sé que esta es una respuesta muy tardía, pero comencé a trabajar en Codable hace solo unos días. Y me topé con un problema similar.

Para convertir la cadena en un número flotante, puede escribir una extensión a KeyedDecodingContainer y llamar al método en la extensión desde init(from decoder: Decoder){}

Para el problema mencionado en este problema, vea la extensión que escribí a continuación;

extension KeyedDecodingContainer { func decodeIfPresent(_ type: Float.Type, forKey key: K, transformFrom: String.Type) throws -> Float? { guard let value = try decodeIfPresent(transformFrom, forKey: key) else { return nil } return Float(value) } func decode(_ type: Float.Type, forKey key: K, transformFrom: String.Type) throws -> Float? { return Float(try decode(transformFrom, forKey: key)) } }

Puede llamar a este método desde el método init(from decoder: Decoder) . Vea un ejemplo a continuación;

init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) taxRate = try container.decodeIfPresent(Float.self, forKey: .taxRate, transformFrom: String.self) }

De hecho, puede utilizar este enfoque para convertir cualquier tipo de datos a cualquier otro tipo. Puede convertir la string to Date , string to bool , string to float , float to int etc.

En realidad, para convertir una cadena en un objeto Fecha, preferiré este enfoque sobre JSONEncoder().dateEncodingStrategy porque si lo escribe correctamente, puede incluir diferentes formatos de fecha en la misma respuesta.

Espero haberte ayudado.


Siempre se puede decodificar manualmente. Entonces, dado:

{ "name": "Bob", "age": 25, "tax_rate": "4.25" }

Tu puedes hacer:

struct Example: Codable { let name: String let age: Int let taxRate: Float init(from decoder: Decoder) throws { let values = try decoder.container(keyedBy: CodingKeys.self) name = try values.decode(String.self, forKey: .name) age = try values.decode(Int.self, forKey: .age) guard let rate = try Float(values.decode(String.self, forKey: .taxRate)) else { throw DecodingError.dataCorrupted(.init(codingPath: [CodingKeys.taxRate], debugDescription: "Expecting string representation of Float")) } taxRate = rate } enum CodingKeys: String, CodingKey { case name, age case taxRate = "tax_rate" } }

Consulte Codificar y decodificar manualmente en Codificación y decodificación de tipos personalizados .

Pero estoy de acuerdo, que parece que debería haber un proceso de conversión de cadena más elegante equivalente a DateDecodingStrategy dada la cantidad de fuentes JSON que hay que devolver incorrectamente los valores numéricos como cadenas.


introduce la descripción del enlace aquí Cómo utilizar JSONDecodable en Swift4
1) obtener la Respuesta JSON y Crear Struct 2) conformar la clase Decodable en Struct 3) Otros pasos en el siguiente Proyecto (Ejemplo simple)