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

如何替换废弃的NSKeyedUnarchiver方法并兼容现有iOS用户?

替换废弃的NSKeyedArchiver/Unarchiver方法,兼容现有用户实现方案

问题背景

现有iOS应用通过UserDefaults存储登录用户数据,当前使用的NSKeyedUnarchiver.unarchiveObject(with:)和NSKeyedArchiver.archivedData(withRootObject:)从iOS 12起已被废弃,虽仍能在新版本iOS运行,但需替换为Apple推荐的安全编码方法,同时不能影响现有用户的已存数据。现有代码如下:

static var userLoginResponse : LoginModel? {
        get {
            if let data = UserDefaults.standard.data(forKey: "userLoginResponse"), let respData = NSKeyedUnarchiver.unarchiveObject(with: data) as? Data {
                return LoginModel(data: respData)
            }
            return nil
        }
        set {
            if let value = newValue?.toJsonData() {
                UserDefaults.standard.setValue(NSKeyedArchiver.archivedData(withRootObject: value), forKey: "userLoginResponse")
            } else {
                UserDefaults.standard.setValue(nil, forKey: "userLoginResponse")
            }
        }
    }

修改思路

  1. 写入逻辑:直接替换为新的archivedData(withRootObject:requiringSecureCoding:error:)方法,启用安全编码(Data默认支持安全编码),同时处理归档错误。
  2. 读取逻辑:优先尝试用新的unarchivedObject(ofClass:from:)方法解码,若失败(说明是老方法存储的数据),再降级使用废弃的老方法解码,确保兼容现有用户数据。

修改后的代码

static var userLoginResponse: LoginModel? {
    get {
        guard let data = UserDefaults.standard.data(forKey: "userLoginResponse") else {
            return nil
        }
        
        // 优先尝试新方法解码
        do {
            if let respData = try NSKeyedUnarchiver.unarchivedObject(ofClass: Data.self, from: data) {
                return LoginModel(data: respData)
            }
        } catch {
            // 新方法解码失败,用老方法兼容旧数据
            if let respData = NSKeyedUnarchiver.unarchiveObject(with: data) as? Data {
                return LoginModel(data: respData)
            }
        }
        
        return nil
    }
    set {
        guard let value = newValue?.toJsonData() else {
            UserDefaults.standard.setValue(nil, forKey: "userLoginResponse")
            return
        }
        
        do {
            // 使用新的归档方法,启用安全编码
            let archivedData = try NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true)
            UserDefaults.standard.setValue(archivedData, forKey: "userLoginResponse")
        } catch {
            // 归档失败时做兜底处理
            UserDefaults.standard.setValue(nil, forKey: "userLoginResponse")
            print("归档用户数据失败:\(error.localizedDescription)")
        }
    }
}

关键说明

  • 安全编码:新方法强制要求启用安全编码(requiringSecureCoding: true),Data类本身已经遵循NSSecureCoding协议,无需额外处理。
  • 兼容逻辑:读取时先尝试新方法,失败后回退到老方法,保证已用老版本应用存储的用户数据仍能正常读取。
  • 错误处理:新增了do-catch块处理归档和解档过程中的错误,提升代码稳定性,避免崩溃。

内容的提问来源于stack exchange,提问作者RP89

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.28 15:43:30