>我正在尝试对服务器执行HTTP请求:内容是一个JSON对象,其中包含键"amount"的数值。如果"amount"是带有十进制数字的值,例如 1.6,则请求将包含该值 1.6000000000000001,并且此值不被服务器接受(API 是 Java 制作的,类型是浮点数。我无法将字符串发送到服务器,因为从我那里接收数据的 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()
如果没有完全重现该问题的代码,很难确定,但我想您看到的是这种行为:
let amount = 1.6 // Double
let jsonObject = ["amount": amount]
let jsonData = try! JSONSerialization.data(withJSONObject: jsonObject)
String(data: jsonData, encoding: String.Encoding.utf8)
Swift 基金会的 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
而不是Double
嵌入到 JSON 中,并且它的格式会有所不同:
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 规范发送浮点数,并且它仍然很可能在接收端解析为浮点数。
如果没有看到您的代码,就很难提供帮助,但是,要检查的一件事是您是否正在使用 NumberFormatter 以确保您的值得到正确的舍入。假设您正在从UITextField中提取数字,那么您将需要这样的东西:
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
if let textValue = textField.value {
var amount = numberFormatter.number(from: textValue)
}