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

Swift unarchivedDictionary解档UserDefaults报NSInvalidArgumentException求解

崩溃原因

两个核心问题导致报错:

  • NSKeyedUnarchiver.unarchivedDictionary的类参数传值完全不符合API设计要求,该方法的两个类参数需要传入字典key、value对应允许的类集合,不能直接传入完整字典类型。
  • 归档时关闭了安全编码开关,生成的归档数据不符合属性列表规范,写入UserDefaults时被系统拦截抛出异常。
正确实现代码
// 归档存储逻辑
let widgetDictionary: [Int: [String: String]] = [:] // 替换为你的实际业务数据
do {
    // 安全解档对应归档必须开启requiresSecureCoding
    let encodedData = try NSKeyedArchiver.archivedData(
        withRootObject: widgetDictionary,
        requiringSecureCoding: true
    )
    UserDefaults.standard.set(encodedData, forKey: "flaggedWidgetDictKey")
} catch {
    print("归档失败:\(error.localizedDescription)")
}

// 解档读取逻辑
guard let outData = UserDefaults.standard.data(forKey: "flaggedWidgetDictKey") else {
    // 无本地存储数据的兜底逻辑
    return
}
do {
    let decodedData = try NSKeyedUnarchiver.unarchivedDictionary(
        keysOfClasses: [NSNumber.self], // Swift Int桥接OC类型为NSNumber
        objectsOfClasses: [NSDictionary.self, NSString.self], // 嵌套字典及内部字符串类型
        from: outData
    ) as? [Int: [String: String]] ?? [:]
    // 后续正常使用decodedData即可
} catch {
    print("解档失败:\(error.localizedDescription)")
}
参数传值规则
  • keysOfClasses:传入字典顶层key所有可能的类类型集合。Swift的Int类型桥接到Objective-C运行时为NSNumber,因此必须传入[NSNumber.self],直接传Int.self或完整字典类型都会导致类型校验失败。
  • objectsOfClasses:传入字典顶层value、以及value嵌套结构中所有可能的类类型集合。你的字典value是[String: String]类型,桥接为OC的NSDictionary,字典内部的键值都是NSString,因此需要同时传入NSDictionary.self和NSString.self,系统会递归校验所有嵌套对象的类型合法性,缺省任何一个类都会触发解档失败。
避坑提示
  • 归档时的requiringSecureCoding参数必须和解档逻辑匹配,使用安全解档方法时归档必须开启该开关,否则会出现类型校验不通过问题。
  • 禁止强制解包outData!,使用guard let做判空处理,避免未存值时解包nil触发崩溃。
  • 之前触发的"Attempt to insert non-property list object"报错,是旧的归档逻辑生成了不符合属性列表规范的数据导致,替换为上述逻辑重新归档存储后即可解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 05:21:47