swift - 从呈现为字符串的 JSON 解析十进制
问题描述
使用 Xcode 10.2 和 iOS 12.x,我们能够从 json 字符串中提取 Decimal。对于 Xcode 11.1 和 iOS 13.1,它会抛出异常
预期解码 Double 但找到了一个字符串/数据。
class MyClass : Codable {
var decimal: Decimal?
}
然后尝试解析它
let json = "{\"decimal\":\"0.007\"}"
let data = json.data(using: .utf8)
let decoder = JSONDecoder()
decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "s1", negativeInfinity: "s2", nan: "s3")
do {
let t = try decoder.decode(MyClass.self, from: data!)
} catch {
print(error)
}
如果我将 json 字符串更改为
let json = "{\"decimal\":0.007}"
它有效,但我们又一次失去了精确度。有任何想法吗?
解决方案
您需要扩展 KeyedDecodingContainer 并为 Decimal.Type 添加一个实现。
extension KeyedDecodingContainer {
func decode(_ type: Decimal.Type, forKey key: K) throws -> Decimal {
let stringValue = try decode(String.self, forKey: key)
guard let decimalValue = Decimal(string: stringValue) else {
let context = DecodingError.Context(codingPath: [key], debugDescription: "The key \(key) couldn't be converted to a Decimal value")
throw DecodingError.typeMismatch(type, context)
}
return decimalValue
}
}
这是一个例子:
let json = """
{
"capAmount": "123.45"
}
"""
struct Status: Decodable {
let capAmount: Decimal
enum CodingKeys: String, CodingKey {
case capAmount
}
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
capAmount = try container.decode(Decimal.self, forKey: .capAmount)
}
}
// Execute it
if let data = json.data(using: .utf8){
let status = try JSONDecoder().decode(Status.self, from: data)
print(status.capAmount)
}
推荐阅读
- rust - 打印 Rust 中的所有结构字段
- python - 如何在 Python 中的工具栏菜单后显示选项卡小部件?
- css - @keyframes 动画未运行
- python-3.x - 使用scrapy脚本时遇到问题(选择链接)
- kdtree - 多边形搜索
- cmake - 安装问题:Cmake 错误:include 找不到加载文件:yarpl-exports.cmake
- amazon-web-services - 关于 EC2 的 AWS 问题在 3:23 小时内关闭,您将在 0、3、4、3:23 或 3.24 小时内收取多少费用?
- angular-material - Angular 8 中的材质图标无法正确显示
- python - 如何手动验证用户
- python-3.x - Windows PySpark 2.4.4 Standalone 无法设置 log4j.properties