Necesito Decodable (protocolo decodificable) un valor decimal impreciso correctamente, a partir de esta pregunta entiendo cómo manejar correctamente la creación de instancias decimales, pero ¿cómo puedo hacer esto al decodificar?
Si intenta iniciar cualquier número como una cadena
if let value = try! container.decode(String.self, forKey: .d) { self.taxAmount = Decimal(string: value) } Obtengo un Fatal Error: "Expected to decode String but found a number instead."
Y si intenta iniciar 130.43 como decimal
if let value = try! container.decode(Decimal.self, forKey: .d) { //value.description is 130.43000000000002048 self.d = Decimal(string: value.description) //making subtotal to be also 130.43000000000002048 and not 130.43 }¿Hay alguna forma de usar cualquiera de estos constructores al decodificar?
NSDecimalNumber(string: "1.66")NSDecimalNumber(value: 166).dividing(by: 100)Decimal(166)/Decimal(100)Decimal(sign: .plus, exponent: -2, significand: 166)Aquí hay una versión simplificada del JSON que recibo del servicio externo:
{ "priceAfterTax": 150.00, "priceBeforeTax": 130.43, "tax": 15.00, "taxAmount": 19.57 }Nota: No puedo cambiar lo que se recibe para decodificarlo, estoy atascado trabajando con números decimales.
Puede implementar su propio método de decodificación, convertir su doble en cadena y usarlo para inicializar sus propiedades decimales:
extension LosslessStringConvertible { var string: String { .init(self) } } extension FloatingPoint where Self: LosslessStringConvertible { var decimal: Decimal? { Decimal(string: string) } } struct Root: Codable { let priceAfterTax, priceBeforeTax, tax, taxAmount: Decimal } extension Root { public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.priceAfterTax = try container.decode(Double.self, forKey: .priceAfterTax).decimal ?? .zero self.priceBeforeTax = try container.decode(Double.self, forKey: .priceBeforeTax).decimal ?? .zero self.tax = try container.decode(Double.self, forKey: .tax).decimal ?? .zero self.taxAmount = try container.decode(Double.self, forKey: .taxAmount).decimal ?? .zero } } let data = Data(""" { "priceAfterTax": 150.00, "priceBeforeTax": 130.43, "tax": 15.00, "taxAmount": 19.57 } """.utf8) let decodedObj = try! JSONDecoder().decode(Root.self, from: data) decodedObj.priceAfterTax // 150.00 decodedObj.priceBeforeTax // 130.43 decodedObj.tax // 15.00 decodedObj.taxAmount // 19.57