用swift在http请求中发送一个数值,在实际值上加上000000000000001
Sending a numeric value in http request with swift, adds 000000000000001 to the actual value
我正在尝试向服务器执行 HTTP 请求:内容是一个 JSON 对象,其中包含键 "amount" 的数值。如果 "amount" 是带有十进制数字的值,例如1.6、请求中会包含值
1.6000000000000001,服务器不接受此值(api 是 Java 并且类型是 float 。我无法向服务器发送字符串,因为接收到的 API我的数据只能接受 "amount" 的数字。我尝试使用 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()
如果没有看到您的代码,很难提供帮助,但是,需要检查的一件事是您是否使用 NumberFormatter 以确保您对值进行了正确的舍入。假设您从 UITextField 中提取数字,那么您将需要这样的东西:
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
if let textValue = textField.value {
var amount = numberFormatter.number(from: textValue)
}
没有完全重现问题的代码,很难确定,但我想你看到的是这种行为:
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 更改格式
如果您出于某种原因只需要以较低的精度对其进行格式化以使其在服务器上通过验证,则可以将其作为 Decimal
而不是 [=] 嵌入到 JSON 中16=] 并且它的格式会有所不同:
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 规范发送浮点数,并且它仍然很可能在接收端.
我正在尝试向服务器执行 HTTP 请求:内容是一个 JSON 对象,其中包含键 "amount" 的数值。如果 "amount" 是带有十进制数字的值,例如1.6、请求中会包含值 1.6000000000000001,服务器不接受此值(api 是 Java 并且类型是 float 。我无法向服务器发送字符串,因为接收到的 API我的数据只能接受 "amount" 的数字。我尝试使用 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()
如果没有看到您的代码,很难提供帮助,但是,需要检查的一件事是您是否使用 NumberFormatter 以确保您对值进行了正确的舍入。假设您从 UITextField 中提取数字,那么您将需要这样的东西:
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
if let textValue = textField.value {
var amount = numberFormatter.number(from: textValue)
}
没有完全重现问题的代码,很难确定,但我想你看到的是这种行为:
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 更改格式
如果您出于某种原因只需要以较低的精度对其进行格式化以使其在服务器上通过验证,则可以将其作为 Decimal
而不是 [=] 嵌入到 JSON 中16=] 并且它的格式会有所不同:
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 规范发送浮点数,并且它仍然很可能在接收端.