使用NSKeyedArchiver/Unarchiver时TimeInterval精度丢失问题求助
解决NSKeyedArchiver/NSKeyedUnarchiver归档[String:Any]字典的问题
嘿,我来帮你搞定这个归档字典的问题!首先得提一句,你用的NSKeyedUnarchiver.unarchiveObject(with:)在iOS 12、macOS 10.14之后已经被标记为废弃了,而且直接处理[String:Any]这种无类型约束的字典,很容易在解码时出现类型不匹配或者解码失败的情况。咱们一步步来修正:
第一步:添加字典的归档扩展
先给Dictionary写一个归档的扩展,专门处理键为字符串类型的字典(毕竟你的键"updated"和"isFavorite"都是字符串):
extension Dictionary where Key == String, Value: Any { /** Encode dictionary to Data using NSKeyedArchiver */ var archive: Data? { do { return try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: false) } catch { print("归档失败:\(error.localizedDescription)") return nil } } }
这里用了当前推荐的archivedData(withRootObject:requiringSecureCoding:)API,requiringSecureCoding设为false是因为字典里的TimeInterval(本质是Double)和Bool都是支持安全编码的基础类型,完全没问题。
第二步:修正Data的解码扩展
把你原来的Data.decode扩展改成更安全的新版本,同时处理可能的错误和类型转换:
extension Data { /** Decode data to [String:Any] using NSKeyedUnarchiver */ var decode: [String:Any]? { do { guard let object = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSDictionary.self], from: self) else { print("解码后对象为空") return nil } return object as? [String:Any] } catch { print("解码失败:\(error.localizedDescription)") return nil } } }
这里用了unarchivedObject(ofClasses:from:),指定解码的根类为NSDictionary——因为Swift的[String:Any]归档后会转成NSDictionary,这种方式比旧方法更安全,还能捕获解码过程中的错误。
第三步:实际使用示例
现在你可以这样完成归档和解码操作:
// 准备要归档的字典 let time: TimeInterval = Date().timeIntervalSince1970 let dataDict: [String:Any] = ["updated": time, "isFavorite": true] // 归档并存储到UserDefaults(也可以存到本地文件) if let archivedData = dataDict.archive { UserDefaults.standard.set(archivedData, forKey: "FavoriteItemData") } // 从UserDefaults取出并解码 if let savedData = UserDefaults.standard.data(forKey: "FavoriteItemData"), let decodedDict = savedData.decode { // 取值时一定要做类型检查,避免崩溃 if let updatedTime = decodedDict["updated"] as? TimeInterval { print("更新时间戳:\(updatedTime)") } if let isFavorite = decodedDict["isFavorite"] as? Bool { print("是否收藏:\(isFavorite)") } }
额外注意点
- 解码时必须做类型校验,比如把
decodedDict["updated"]转成TimeInterval(也就是Double),不要直接强制转换,否则容易引发崩溃。 - 如果后续字典要加入自定义对象,必须让对象遵守
NSCoding或者Codable协议,不然归档会失败。 - 要是你的项目支持iOS 13+、macOS 10.15+,其实更推荐用
Codable协议来做序列化/反序列化,比NSKeyedArchiver更简洁安全;但如果必须用NSKeyedArchiver,上面的代码完全能满足需求。
内容的提问来源于stack exchange,提问作者adnv
相关产品推荐
相关产品推荐

