You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:33:50