当数据是字典时,如何将NSKeyedUnarchiver.unarchiveTopLevelObjectWithData替换为unarchivedObject

How to replace NSKeyedUnarchiver.unarchiveTopLevelObjectWithData with unarchivedObject when data is a Dictionary

提问人:Jordan H 提问时间:3/4/2023 最后编辑:Jordan H 更新时间:4/15/2023 访问量:1308

问:

iOS 16.4 弃用了 unarchiveTopLevelObjectWithData(_:),应替换为 unarchivedObject(ofClass:from:)。

当您存档 Swift 词典时,例如 ,如何使用较新的 API 来取消存档它?[String: Any]

NSKeyedUnarchiver.unarchivedObject(ofClass: [String: Any].self, from: data)导致生成时错误:

静态方法“unarchivedObject(ofClass:from:)”要求“[String : Any]”符合“NSCoding”

//create the data from dictionary
let dictionary: [String: Any] = ["Text": "Hello", "Number": 1, "Array": ["Hello", "World"]]
let data = try! NSKeyedArchiver.archivedData(withRootObject: dictionary, requiringSecureCoding: true)

//and later get the dictionary from the data
let dictionary = try? NSKeyedUnarchiver.unarchivedObject(ofClass: [String: Any].self, from: data) //sorry no can do
iOS Swift nskeyedunarchiver

评论

0赞 HangarRash 3/4/2023
尝试取消存档并将最终结果转换为 。 在 Swift 中应该避免使用,字典也应该避免使用。在 Swift 中使用 struct 和 Codable 以获得更好的类型安全性。NSDictionary[String: Any]NSKeyed[Un]ArchiverAny
0赞 Jordan H 3/4/2023
@HangarRash 尝试使用 NSDictionary throws 在这个用例中,值实际上可以是任何东西,并且键是未知的。Error Domain=NSCocoaErrorDomain Code=4864 "value for key 'NS.objects' was of unexpected class 'NSArray' (0x20a9295a0) [/System/Library/Frameworks/CoreFoundation.framework].
0赞 Alexander 3/4/2023
@JordanH 错误消息可能是正确的。与您的期望相反,该存档包含数组,而不是字典。
0赞 Jordan H 3/4/2023
是的,在此示例中,字典确实包含其值之一的数组@Alexander
0赞 Alexander 3/4/2023
@JordanH我很好奇,如果你使用 ?NSDictionary<NSObject, NSObject>

答:

8赞 HangarRash 3/4/2023 #1

由于 Swift 字典的类型不符合 ,因此您需要回退到使用 .由于您还使用安全编码,因此还需要列出字典中可以包含的所有类型。[String: Any]NSCodingNSDictionary

您将需要使用该方法,以便可以列出所有类。unarchivedObject(ofClasses:from:)

let dictionary = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: [NSDictionary.self, NSArray.self], from: data) as? NSDictionary

您最终可能还需要将 和 添加到类列表中。继续添加错误消息中显示的类,直到它正常工作。NSString.selfNSNumber.self

评论

0赞 Jordan H 3/5/2023
这行得通!我必须添加 NSDictionary、NSArray、NSString、NSNumber、NSDate 和 NSData。这就是 plist 可以包含的所有内容。我将按照 Larme 的建议切换到使用,并且需要将此解决方案用于遗留数据。谢谢!PropertyListSerialization
-1赞 user2819640 4/15/2023 #2

您可以使用以下虚拟对象:而不是 . 这样,您就可以涵盖所有 NS 案例。 它对我有用,尽管出现了紫色消息(Apple 始终处于安全状态。不错,但是......[NSObject.self][NSDictionary.self, NSArray.self ...... ]

-[NSKeyedUnarchiver validateAllowedClass:forKey:]:NSSecureCoding 允许的类列表包含 [NSObject 类],该类通过允许隐式解码任何 Objective-C 类来绕过安全性。请考虑在解码过程中通过仅列出要解码的类或比 NSObject 更具体的基类来缩小解码期间允许的类的范围。这将在将来成为一个错误。允许的类列表:{( “'NSObject' (0x219ef2d98) [/usr/lib]” )}

评论

3赞 HangarRash 4/15/2023
警告是有原因的。您真的不想只使用 NSObject。它违背了使用安全编码的全部意义。