`cannotDecodeObjectOfClassName` 未在 `NSKeyedArchiverDelegate` 中调用

`cannotDecodeObjectOfClassName` not invoked in `NSKeyedArchiverDelegate`

我正在尝试捕获 NSKeyedUnarchiver 解压缩异常 NSInvalidUnarchiveOperationException,其中一个未知的 class 正在通过 NSSecureCoding 协议安全解码。

我正在使用的解决方案是基于相关的 通过实现委托协议 NSKeyedUnarchiverDelegate 所以我可以通过 unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:) 监听和响应异常。但是,在解码过程中遇到未知class时,似乎不会调用此委托方法。

这是我用于安全地取消归档数组对象的代码片段。

func securelyUnarchiveArrayOfCustomObject(from url: URL, for key: String) -> [MyCustomClass]? {
    guard let data = try? Data(contentsOf: url) else {
        os_log("Unable to locate data at given url.path: %@", log: OSLog.default, type: .error, url.path)
        return nil
    }

    let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
    let delegate = UnarchiverDelegate()     // Prevents `NSInvalidUnarchiveOperationException` crash
    unarchiver.delegate = delegate
    unarchiver.requiresSecureCoding = true  // Prevents object substitution attack

    let allowedClasses = [NSArray.self] // Will decode without problem if using [NSArray.self, MyCustomClass.self]
    let decodedObject = unarchiver.decodeObject(of: allowedClasses, forKey: key)
    let images = decodedObject as! [ImageWithCaption]?
    unarchiver.finishDecoding()

    return images
}

我的 UnarchiverDelegate 的实现就像我指出的原始 中一样。在我的设置下,decodeObject(of: allowedClasses, forKey: key) 不会抛出异常,而是引发运行时异常:

'NSInvalidUnarchiveOperationException', reason: 
'value for key 'NS.objects' was of unexpected class 
'MyCustomClassProject.MyCustomClass'. Allowed classes are '{(
    NSArray
)}'.'

这应该只是 NSKeyedUnarchiverDelegateunarchiver(_:cannotDecodeObjectOfClassName:originalClasses:) 应该被调用的那种异常,基于 its documentation:

Informs the delegate that the class with a given name is not available during decoding.

但在我的例子中,这个方法没有被上面的代码片段调用(即使其他委托方法,如 unarchiverWillFinish(_:)unarchiver(_:didDecode:) 在解码没有遇到问题时被正常调用.

不像原来的post,我不能像decodeTopLevelObjectForKey一样使用class函数,我可以用try?处理异常,因为我需要支持使用 NSSecureCoding 协议的安全编码和解码, 如所讨论的 here。这迫使我使用 decodeObject(of:forKey),它不会抛出任何我可以处理的异常,而且,在抛出导致应用程序崩溃的运行时异常之前,它也不会通知我的委托。

委托方法unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:)在什么场景下才真正被调用?我如何在 NSSecureCoding 设置下收听 NSInvalidUnarchiveOperationException 并做出反应,以便在解码不成功时避免运行时崩溃?

有人在 Apple Dev Forum 上帮助了我。详情见:

https://forums.developer.apple.com/thread/76664