NSKeyedArchiver,NSKeyedUnarchiver和TimeInterval舍入超过7位小数

时间:2018-03-31 23:17:07

标签: ios swift nskeyedarchiver nskeyedunarchiver

使用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!)")

如果时间变量包含&lt; = 6位小数,但是得到&gt; = 7位小数位数并且舍入,则一切正常。

示例正确

  • 归档前的数据:[&#34;已更新&#34;:1522537700。 689399 , &#34; isFavorite&#34;:true]
  • 取消归档后的数据:[&#34;更新&#34;: 1522537700. 689399 ,&#34; isFavorite&#34;:1]

示例不正确

  • 归档前的数据:[&#34;已更新&#34;:1522536585。 2104979 , &#34; isFavorite&#34;:true]
  • 取消归档后的数据:[&#34;更新&#34;: 1522536585。 210498 ,&#34; isFavorite&#34;:1]

1 个答案:

答案 0 :(得分:3)

正如@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原生的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]