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

已添加NSString等类仍触发NSKeyedUnarchiver未显式包含类警告

NSKeyedUnarchiver解归档自定义数组时的警告问题

我用以下代码从UserDefaults解归档自定义对象数组:

guard let data = UserDefaults.standard.data(forKey: "key") else {
    return 
}

let customClassArray = try NSKeyedUnarchiver.unarchivedObject(ofClasses: 
   [NSMutableArray.self, 
    NSNull.self, 
    NSMutableDictionary.self, 
    NSNumber.self, 
    NSString.self, 
    NSArray.self, 
    CustomClass.self], from: data) as? [CustomClass]

但反复收到这类警告:

[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSString' (0x1e5fae918) [/System/Library/Frameworks/Foundation.framework]' for key 'NS.keys', even though it was not explicitly included in the client allowed classes set: '{( "'NSMutableArray' (0x1e5fa7050) [/System/Library/Frameworks/CoreFoundation.framework]", "'NSNull' (0x1e5fa68a8) [/System/Library/Frameworks/CoreFoundation.framework]", "'NSMutableDictionary' (0x1e5fa6fb0) [/System/Library/Frameworks/CoreFoundation.framework]" )}'. This will be disallowed in the future.

以及:

[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSNumber' (0x1e5fae8c8) [/System/Library/Frameworks/Foundation.framework]' for key 'NS.objects', even though it was not explicitly included in the client allowed classes set: '{( "'NSMutableArray' (0x1e5fa7050) [/System/Library/Frameworks/CoreFoundation.framework]", "'NSNull' (0x1e5fa68a8) [/System/Library/Frameworks/CoreFoundation.framework]", "'NSMutableDictionary' (0x1e5fa6fb0) [/System/Library/Frameworks/CoreFoundation.framework]"

明明我已经在allowedClasses里列出了NSString、NSNumber这些类,为什么还是会触发警告?


问题原因与解决方法

核心原因

警告里显示的允许类集合仅包含NSMutableArray、NSNull、NSMutableDictionary,说明你传入的完整类列表未被正确识别。大概率是以下原因导致:

  • 调用unarchivedObject(ofClasses:from:)时,同时传入可变和不可变容器类(比如NSMutableArray和NSArray),导致NSKeyedUnarchiver在验证时优先匹配可变容器,但未正确关联容器内元素的允许类。
  • 历史归档数据是用旧逻辑生成的,解归档时的类列表无法被容器类正确继承传递。

解决步骤

  1. 简化允许类列表,优先使用不可变容器类
    将NSMutableArray.self替换为NSArray.self,NSMutableDictionary.self替换为NSDictionary.self——解归档时,不可变容器类会自动兼容对应的可变类型,同时能正确传递内部元素的允许类。修改后的代码:

    let customClassArray = try NSKeyedUnarchiver.unarchivedObject(ofClasses: 
       [NSArray.self, 
        NSNull.self, 
        NSDictionary.self, 
        NSNumber.self, 
        NSString.self, 
        CustomClass.self], from: data) as? [CustomClass]
    
  2. 检查CustomClass的归档逻辑
    确认CustomClass的init?(coder:)和encode(with:)方法中,所有属性的类型都已包含在允许类列表里。比如如果类内有NSString、NSNumber类型的属性,必须确保这些类被显式加入allowedClasses。

  3. 清理旧归档数据
    若之前用不同的类列表归档过数据,残留数据可能引发验证异常。可以先清除UserDefaults中对应key的数据,重新归档测试:

    UserDefaults.standard.removeObject(forKey: "key")
    

额外说明

苹果在iOS 12及以上版本强化了NSKeyedUnarchiver的安全校验,即使是plist安全类型,若未显式加入允许类列表,未来版本会直接禁止解归档,因此必须确保所有涉及的类(包括容器内的元素类)都被明确添加。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:33:07