在Swift 4中从JSON中解析诸如1.0之类的双精度而不会丢失小数?

时间:2018-01-19 10:20:34

标签: ios json swift

或者我可以检查一个数字是否被解码为十进制数而不是整数?

if let int = any as? Int {
  print("Object in an integer")        
} else if let num = any as? Double {
  print("Object in a double")
}

,其中“any”是JSON文件中的Any值和= 1.0(不是字符串)。 “any”可以强制转换为整数和双精度(因此我检查的顺序决定结果),但我想保留JSON文件中的原始格式。

使用以下行完成解码:

let json = try JSONSerialization.jsonObject(with: data, options: [])

编辑:我已经尝试过检查CFType,但是对于1和1.0都是一样的(灵感来自http://stackoverflow.com/a/30223989/1694526

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

正如@Sulthan已经提到的那样,在JSONSerialization所使用的级别上,这是不可能的,并且应该使用单个类来表示值,并且可能无法确定其类型。

您可以尝试找一些其他工具来检查值,但它确实有意义吗?

  1. 您正在尝试寻找IntDouble之间的差异,但64或32位呢?还是签名和未签名?我们通常不会将它们写成字符串,因此实际上无法区分它们。所以这样做真的没有一般逻辑。
  2. 您确定返回的JSON将始终具有" .0"为这些值附加?这实际上取决于系统,因为JSON标准不包括数字精度,因此最小化优化会减少。例如,如果我使用JSONSerialization并打印出String(data: (try! JSONSerialization.data(withJSONObject: [ "value": 1.0 ], options: .prettyPrinted)), encoding: .utf8),我会收到:{\n \"value\" : 1\n}这意味着它已经修剪了" .0"反正。
  3. 我觉得很难理解这在结构上会有多好。如果需要将这些数据保存到数据库中,则需要定义用于保存数据的基元的大小和类型。如果你需要使用一些算术,你再次需要指定类型......
  4. 唯一的方法是将它用作显示字符串。但在这种情况下,您的值应该以字符串形式返回,而不是数字。

答案 1 :(得分:0)

解决方案是先解析为NSNumber,然后解析为Decimal(或NSDecimalNumber)。不要通过Double进行解析。

let jsonString = "[ 4.01 ]"
let jsonData = jsonString.data(using: .utf8)!
let jsonArray = try! JSONSerialization.jsonObject(with: jsonData, options: []) as! [Any]

// This is the WRONG way to parse decimals (via a Double)
// parseAttemptA = 4.009999999999998976
let parseAttemptA: Decimal = Decimal(jsonArray[0] as! Double)

// This is the CORRECT way to parse decimals (via an NSNumber)
// parseAttemptB = 4.01
let parseAttemptB: Decimal = (jsonArray[0] as! NSNumber).decimalValue

这是一个操场的屏幕截图...

Correct Parsing of Decimal in Swift