4

我正在尝试向服务器执行 HTTP 请求:内容是 JSON 对象,其中包含键“数量”的数值。如果“金额”是带十进制数字的值,例如 1.6,则请求将包含值 1.6000000000000001,并且服务器不接受此值(api 是 Java 制作的,类型是 float 。我无法发送到服务器的字符串,因为从我那里接收数据的 API 只能接受“金额”的数字。我尝试使用 Siesta Framework 或 dataTask 执行请求,但结果始终相同

这就是我创建请求的方式(我省略了不太重要的部分)

let jsonData = try! JSONSerialization.data(withJSONObject: jsonObject) // jsonObject contains the Double value "amount"
let request = URLRequest(url: url)
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request)    
task.resume()
4

2 回答 2

7

如果没有完全重现问题的代码,很难确定,但我想你看到的是这种行为:

let amount = 1.6  // Double
let jsonObject = ["amount": amount]
let jsonData = try! JSONSerialization.data(withJSONObject: jsonObject)
String(data: jsonData, encoding: String.Encoding.utf8)

Swift Foundation 的 JSON 序列化总是将数值格式化为全精度——因此双精度数 1.6 被格式化为1.6000000000000001.

解决方案 1:发送字符串

如果服务器接受它,您可以并且应该发送一个字符串:

let amount = "1.6"  // String
let jsonObject = ["amount": amount]
let jsonData = try! JSONSerialization.data(withJSONObject: jsonObject)
String(data: jsonData, encoding: String.Encoding.utf8)

请注意,如果您正在处理金钱或其他任何需要精确值的事物,则字符串是发送此值的唯一正确方法:即使您将其拼写为1.6,标准 JSON 解析器也可能会将其转换为接收端的浮点数.

解决方案 2:使用 Decimal 更改格式

如果您只是需要以较低的精度对其进行格式化以使其由于某种原因通过服务器上的验证,则可以将其作为 aDecimal而不是 a嵌入到 JSON 中,Double并且它的格式会有所不同:

let amount = 1.6
let jsonObject = ["amount": Decimal(amount)]
let jsonData = try! JSONSerialization.data(withJSONObject: jsonObject)
String(data: jsonData, encoding: String.Encoding.utf8)
// {"amount":1.6}

您甚至可以操纵Decimal以四舍五入到一定的精度。

但是请注意,这并不能避免浮点精度问题:您仍然根据 JSON 规范发送浮点数,并且它仍然很可能在接收端被解析为浮点数。

于 2018-01-19T02:00:14.810 回答
0

如果没有看到您的代码,很难提供帮助,但是,要检查的一件事是您是否使用 NumberFormatter 来确保您对值进行了正确的舍入。假设您从 UITextField 中提取数字,那么您将需要这样的东西:

let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
if let textValue = textField.value {
    var amount = numberFormatter.number(from: textValue)
}
于 2018-01-18T11:54:36.440 回答