NSKeyedUnarchiver新方法返回nil,旧废弃方法却可正常解析
NSKeyedUnarchiver新方法返回nil的排查原因
- 嵌套类型未被明确允许
旧方法unarchiveTopLevelObjectWithData会自动兼容容器内的各种嵌套类型,但新方法unarchivedObject(ofClass:from:)需要明确指定所有可能出现的类。如果你的NSDictionary里包含了NSMutableDictionary、NSMutableString这类子类,或者自定义类,只传入NSDictionary.self会导致类型校验失败,直接返回nil。
解决方式:改用unarchivedObject(ofClasses:from:),传入所有允许的类集合:
let allowedClasses: [AnyClass] = [NSDictionary.self, NSString.self, NSNumber.self, NSData.self, NSMutableDictionary.self] guard let unarchivedData = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: allowedClasses, from: archivedData) as? NSDictionary else { // 处理解析失败逻辑 return }
- 顶层类型与指定类不匹配
旧方法不限制顶层对象类型,哪怕归档的顶层是NSArray,你强转成NSDictionary也能拿到结果(只是可能后续操作出错)。但新方法会严格校验顶层类型,如果实际归档的顶层不是NSDictionary,指定NSDictionary.self就会返回nil。
排查方式:先不限制类型,看看实际顶层对象是什么:
do { let topObject = try NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSObject.self], from: archivedData) print("顶层对象类型:\(type(of: topObject))") } catch { print(error) }
- 安全编码限制导致解析失败
旧方法默认允许解析未启用安全编码的归档数据,而新方法默认开启严格的安全编码校验。如果你的归档数据是用旧版NSKeyedArchiver生成的(未设置requiresSecureCoding为false),新方法会拒绝解析。
解决方式:手动初始化NSKeyedUnarchiver并关闭安全编码校验,同时捕获具体错误:
do { let unarchiver = try NSKeyedUnarchiver(forReadingFrom: archivedData) unarchiver.requiresSecureCoding = false guard let unarchivedData = unarchiver.decodeTopLevelObject(forKey: NSKeyedArchiveRootObjectKey) as? NSDictionary else { throw NSError(domain: "解析错误", code: -1, userInfo: [NSLocalizedDescriptionKey: "顶层对象不是NSDictionary"]) } unarchiver.finishDecoding() // 使用解析后的数据 } catch { print("解析失败:\(error)") }
try?吞掉了关键错误信息
你之前用try?会忽略所有错误,导致无法得知具体失败原因。必须改用do/catch结构,直接用try而不是try?,才能获取到详细的错误日志,比如类型不匹配、编码格式错误等。
示例代码:
do { let unarchivedData = try NSKeyedUnarchiver.unarchivedObject(ofClass: NSDictionary.self, from: archivedData) } catch { print("解析错误详情:\(error.localizedDescription)") }
内容的提问来源于stack exchange,提问作者Mike Nathas
相关产品推荐
相关产品推荐

