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
相关产品推荐
相关产品推荐

