如何使用 Swift 中的 Decoadable 对象将任何 json 值解码为字符串?
How to decode any json value to string with Decoadable object in Swift?
根据我的问题,我想将 json 的每个字段解码为字符串值。
我的json长这样
{ name: "admin_tester",
price: 99.89977202,
no: 981,
id: "nfs-998281998",
amount: 98181819911019.828289291329 }
我想像这样创建我的结构
struct StockNFS: Decodable {
let name: String?
let price: String?
let no: String?
let id: String?
let amount: String?
}
但是如果我这样声明我的结构,当我使用 json 解码时我会得到错误不匹配类型
之所以要将每个值映射到字符串,是因为如果我对 price
和 amount
使用双精度或小数,编码后有时值会不正确。例如0.125,我会得到0.124999999.
我只想接收字符串类型的任何数据,以便仅在 ui 上显示(不编辑或操作值)
如有任何帮助,我将不胜感激。非常感谢。
为避免浮点数问题,我们可以为键的价格和金额使用字符串或小数类型。在任何一种情况下,我们都不能直接解码为任何一种类型,但我们首先需要使用给定的类型,即 Double,因此我们需要为此自定义初始化。
第一种情况是使用 String(我认为没有理由将可选字段用作默认值,如果任何字段实际上可以为 nil,请更改此设置)
struct StockNFS: Codable {
let name: String
let price: String
let no: Int
let id: String
let amount: String
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
let priceValue = try container.decode(Double.self, forKey: .price)
price = "\(priceValue.roundToDecimal(8))"
//... rest of the values
}
}
四舍五入的方法灵感来自this优秀答案
extension Double {
func roundToDecimal(_ fractionDigits: Int) -> Double {
let multiplier = pow(10, Double(fractionDigits))
return (self * multiplier).rounded() / multiplier
}
}
做同样的事情,但使用数字类型Decimal
我们做
struct StockNFS2: Codable {
let name: String
let price: Decimal
let no: Int
let id: String
let amount: Decimal
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
let priceValue = try container.decode(Double.self, forKey: .price)
price = Decimal(priceValue).round(.plain, precision: 8)
//... rest of the values
}
}
舍入方法再次受到同一个答案的启发
extension Decimal {
func round(_ mode: Decimal.RoundingMode, precision: Int = 2) -> Decimal {
var result = Decimal()
var value = self
NSDecimalRound(&result, &value, precision, mode)
return result
}
}
根据我的问题,我想将 json 的每个字段解码为字符串值。
我的json长这样
{ name: "admin_tester",
price: 99.89977202,
no: 981,
id: "nfs-998281998",
amount: 98181819911019.828289291329 }
我想像这样创建我的结构
struct StockNFS: Decodable {
let name: String?
let price: String?
let no: String?
let id: String?
let amount: String?
}
但是如果我这样声明我的结构,当我使用 json 解码时我会得到错误不匹配类型
之所以要将每个值映射到字符串,是因为如果我对 price
和 amount
使用双精度或小数,编码后有时值会不正确。例如0.125,我会得到0.124999999.
我只想接收字符串类型的任何数据,以便仅在 ui 上显示(不编辑或操作值)
如有任何帮助,我将不胜感激。非常感谢。
为避免浮点数问题,我们可以为键的价格和金额使用字符串或小数类型。在任何一种情况下,我们都不能直接解码为任何一种类型,但我们首先需要使用给定的类型,即 Double,因此我们需要为此自定义初始化。
第一种情况是使用 String(我认为没有理由将可选字段用作默认值,如果任何字段实际上可以为 nil,请更改此设置)
struct StockNFS: Codable {
let name: String
let price: String
let no: Int
let id: String
let amount: String
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
let priceValue = try container.decode(Double.self, forKey: .price)
price = "\(priceValue.roundToDecimal(8))"
//... rest of the values
}
}
四舍五入的方法灵感来自this优秀答案
extension Double {
func roundToDecimal(_ fractionDigits: Int) -> Double {
let multiplier = pow(10, Double(fractionDigits))
return (self * multiplier).rounded() / multiplier
}
}
做同样的事情,但使用数字类型Decimal
我们做
struct StockNFS2: Codable {
let name: String
let price: Decimal
let no: Int
let id: String
let amount: Decimal
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
name = try container.decode(String.self, forKey: .name)
let priceValue = try container.decode(Double.self, forKey: .price)
price = Decimal(priceValue).round(.plain, precision: 8)
//... rest of the values
}
}
舍入方法再次受到同一个答案的启发
extension Decimal {
func round(_ mode: Decimal.RoundingMode, precision: Int = 2) -> Decimal {
var result = Decimal()
var value = self
NSDecimalRound(&result, &value, precision, mode)
return result
}
}