NSKeyedArchiver、NSKeyedUnarchiver 和 TimeInterval 四舍五入超过 7 位小数
NSKeyedArchiver, NSKeyedUnarchiver and TimeInterval rounding more than 7 decimal places
我在使用 NSKeyedArchiver、NSKeyedUnarchiver 时遇到问题。
我需要存档字典 ["updated": time, "isFavorite": true]
,其中时间是自 1970 年以来的时间间隔。
我的代码如下所示:
import Foundation
extension Data {
/** Decode data and returns Dictionary<String,Any>, use NSKeyedUnarchiver decoder */
var decode: [String:Any]? {
return NSKeyedUnarchiver.unarchiveObject(with: self) as? [String:Any]
}
}
extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any {
/** Encode Dictionary<String,Any> to the data, use NSKeyedUnarchiver encoder */
var encode: Data? {
return NSKeyedArchiver.archivedData(withRootObject: self)
}
}
/** The current time since 1970 */
var time: Double {
return Date().timeIntervalSince1970 // example 1491800604.362141
}
//////TEST
let payload: Dictionary<String,Any> = ["updated": time, "isFavorite": true]
print("Data before archiving: \(payload)")
let encodePayload = payload.encode
let decodePayload = encodePayload?.decode
print("Data after unarchive: \(decodePayload!)")
如果时间变量包含 <= 6 位小数,一切正常,但我得到 >= 7 位小数并且是 rounded。
示例正确
- 归档前的数据:["updated": 1522537700.689399,
"isFavorite": 真]
- 解压后的数据:["updated":
1522537700.689399, "isFavorite": 1]
示例不正确
- 归档前数据:["updated":1522536585.2104979,
"isFavorite": 真]
- 解压后的数据:["updated":
1522536585.210498, "isFavorite": 1]
正如@rmaddy 所指出的,这是 Double
类型精度的限制:
let payload: Dictionary<String,Any> = ["updated": 1522536585.2104979 as Double, "isFavorite": true]
print("Data before archiving: \(payload)")
let encodePayload = payload.encode
let decodePayload = encodePayload?.decode
print("Data after unarchive: \(decodePayload!)")
输出:
Data before archiving: ["updated": 1522536585.2104979, "isFavorite": true]
Data after unarchive: ["updated": 1522536585.210498, "isFavorite": 1]
但是,您可以使用 NSDecimalNumber
:
更精确地归档内容
let decimalNumber = NSDecimalNumber(mantissa: 15225365852104979, exponent: -7, isNegative: false)
let payload: Dictionary<String,Any> = ["updated": decimalNumber, "isFavorite": true]
print("Data before archiving: \(payload.description)")
let encodePayload = payload.encode
let decodePayload = encodePayload?.decode
print("Data after unarchive: \(decodePayload!.description)")
输出:
Data before archiving: ["updated": 1522536585.2104979, "isFavorite": true]
Data after unarchive: ["updated": 1522536585.2104979, "isFavorite": 1]
您也可以使用 Swift-native Decimal
而不是 NSDecimalNumber
,但是由于某种原因,它的初始化程序的文档非常少,使用起来也很尴尬:
// If you ever end up compiling for a big-endian architecture,
// the byte ordering here may need to be reversed.
// Of course it's not possible to test whether that's actually true at present.
let decimal = Decimal(_exponent: -7, _length: 56, _isNegative: 0, _isCompact: 0, _reserved: 0, _mantissa: (0xa913, 0xbb30, 0x1763, 0x0036, 0, 0, 0, 0))
let payload: Dictionary<String,Any> = ["updated": decimal, "isFavorite": true]
print("Data before archiving: \(payload.description)")
let encodePayload = payload.encode
let decodePayload = encodePayload?.decode
print("Data after unarchive: \(decodePayload!.description)")
输出:
Data before archiving: ["updated": 1522536585.2104979, "isFavorite": true]
Data after unarchive: ["updated": 1522536585.2104979, "isFavorite": 1]
我在使用 NSKeyedArchiver、NSKeyedUnarchiver 时遇到问题。
我需要存档字典 ["updated": time, "isFavorite": true]
,其中时间是自 1970 年以来的时间间隔。
我的代码如下所示:
import Foundation
extension Data {
/** Decode data and returns Dictionary<String,Any>, use NSKeyedUnarchiver decoder */
var decode: [String:Any]? {
return NSKeyedUnarchiver.unarchiveObject(with: self) as? [String:Any]
}
}
extension Dictionary where Key: ExpressibleByStringLiteral, Value: Any {
/** Encode Dictionary<String,Any> to the data, use NSKeyedUnarchiver encoder */
var encode: Data? {
return NSKeyedArchiver.archivedData(withRootObject: self)
}
}
/** The current time since 1970 */
var time: Double {
return Date().timeIntervalSince1970 // example 1491800604.362141
}
//////TEST
let payload: Dictionary<String,Any> = ["updated": time, "isFavorite": true]
print("Data before archiving: \(payload)")
let encodePayload = payload.encode
let decodePayload = encodePayload?.decode
print("Data after unarchive: \(decodePayload!)")
如果时间变量包含 <= 6 位小数,一切正常,但我得到 >= 7 位小数并且是 rounded。
示例正确
- 归档前的数据:["updated": 1522537700.689399, "isFavorite": 真]
- 解压后的数据:["updated": 1522537700.689399, "isFavorite": 1]
示例不正确
- 归档前数据:["updated":1522536585.2104979, "isFavorite": 真]
- 解压后的数据:["updated": 1522536585.210498, "isFavorite": 1]
正如@rmaddy 所指出的,这是 Double
类型精度的限制:
let payload: Dictionary<String,Any> = ["updated": 1522536585.2104979 as Double, "isFavorite": true]
print("Data before archiving: \(payload)")
let encodePayload = payload.encode
let decodePayload = encodePayload?.decode
print("Data after unarchive: \(decodePayload!)")
输出:
Data before archiving: ["updated": 1522536585.2104979, "isFavorite": true]
Data after unarchive: ["updated": 1522536585.210498, "isFavorite": 1]
但是,您可以使用 NSDecimalNumber
:
let decimalNumber = NSDecimalNumber(mantissa: 15225365852104979, exponent: -7, isNegative: false)
let payload: Dictionary<String,Any> = ["updated": decimalNumber, "isFavorite": true]
print("Data before archiving: \(payload.description)")
let encodePayload = payload.encode
let decodePayload = encodePayload?.decode
print("Data after unarchive: \(decodePayload!.description)")
输出:
Data before archiving: ["updated": 1522536585.2104979, "isFavorite": true]
Data after unarchive: ["updated": 1522536585.2104979, "isFavorite": 1]
您也可以使用 Swift-native Decimal
而不是 NSDecimalNumber
,但是由于某种原因,它的初始化程序的文档非常少,使用起来也很尴尬:
// If you ever end up compiling for a big-endian architecture,
// the byte ordering here may need to be reversed.
// Of course it's not possible to test whether that's actually true at present.
let decimal = Decimal(_exponent: -7, _length: 56, _isNegative: 0, _isCompact: 0, _reserved: 0, _mantissa: (0xa913, 0xbb30, 0x1763, 0x0036, 0, 0, 0, 0))
let payload: Dictionary<String,Any> = ["updated": decimal, "isFavorite": true]
print("Data before archiving: \(payload.description)")
let encodePayload = payload.encode
let decodePayload = encodePayload?.decode
print("Data after unarchive: \(decodePayload!.description)")
输出:
Data before archiving: ["updated": 1522536585.2104979, "isFavorite": true]
Data after unarchive: ["updated": 1522536585.2104979, "isFavorite": 1]