NSKeyedUnarchiver - 需要尝试/捕获吗?

Mar*_*rio 20 exception objective-c try-catch nskeyedunarchiver

据我所知,@try/@catch不鼓励使用块,因为exceptions只应抛出不可恢复的灾难性错误(请参阅本讨论,并提供@bbum的好答案:iOS中的异常Handeling).

所以我查看了我的代码并发现了一个@try/@catch我不知道如何摆脱的块:

NSData *fileData = [NSData dataWithContentsOfFile: ....];

NSDictionary *dictionary;

@try {
   dictionary = [NSKeyedUnarchiver unarchiveObjectWithData: fileData];
}
@catch (NSException *exception) {
   //....
}
@finally {
  //...
}
Run Code Online (Sandbox Code Playgroud)

问题是(如文档中所述)+unarchiveObjectWithData:会引发一个NSInvalidArchiveOperationExceptionif NSData不包含有效存档的情况.

由于数据是由用户选择的文件提供的,因此无法保证它包含有效的存档,因此如果选择了错误的文件,应用程序将崩溃.

现在有两个问题:

  1. 如果存档无效,为什么不+unarchiveObjectWithData:返回nil(编辑:和a NSError**)(这似乎不符合灾难性或不可恢复的错误).
  2. 上面的模式是否正确(使用@try)?我找不到任何方法可以让我们事先检查数据是否包含有效的存档,并且发现无法使用委托协议处理这种情况.Antyhing我忽略了?

请注意,上面的代码当然有效,我只是想知道它是否是最佳实践.

Sen*_*ful 18

在iOS 9中为NSKeyedUnarchiver添加了一个新方法,现在返回一个错误:

迅速:

public class func unarchiveTopLevelObjectWithData(data: NSData) throws -> AnyObject?
Run Code Online (Sandbox Code Playgroud)

Objective-C的:

+ (nullable id)unarchiveTopLevelObjectWithData:(NSData *)data error:(NSError **)error;
Run Code Online (Sandbox Code Playgroud)

但是,这与以前版本的iOS不向后兼容,因此您需要检查框架可用性.


Nik*_*uhe 9

NSKeyedArchiver是由Apple建造的.它们控制执行时unarchiveObjectWithData:执行的代码,因此它们还在异常处理期间控制资源管理(这是Objective-C中异常背后的问题源).

如果他们可以保证在你的调用unarchiveObjectWithData:和他们提出异常的代码中的点之间没有外来代码(既不是第三方也不是你的应用程序的代码),理论上可以安全地使用异常,只要调用代码需要保养正确.

问题是这种假设可能不是这样的:通常NSKeyedArchiver用于序列化自定义对象.通常,自定义类实现initWithCoder:读取类数据(通过使用archiver的方法decodeObjectForKey:).

如果归档程序在其中一种方法中抛出异常,则无法修复归档程序的资源处理.异常将通过自定义对象抛出initWithCoder:.归档程序不知道清理的内容是否比反序列化的对象更多.因此,在这种情况下,异常的发生意味着进程处于危险状态,并且可能导致不需要的行为.

关于你的问题:

为什么[NSKeyedArchiver没有使用正确的Cocoa错误处理]?

只有构建归档器的Apple工程师才知道.我的猜测是异常处理和键控归档是在大约同一时间(大约在2001年)建立的,此时尚不清楚异常处理永远不会成为Objective-C中的一等公民.

@try模式是否正确?

由于上述警告的限制,这是正确的.如果 Apple的代码正确处理异常情况并且您自己的序列化代码执行相同的操作,那么@try模式可能是正确的.

但是,要实现完全正确是非常困难的.您必须确保所有执行的代码都知道异常并正确清理.

例如,ARC 默认情况下不会对局部变量和临时对象进行异常清理(您必须启用-fobjc-arc-exceptions此操作).

此外,没有关于@synthesized属性的访问器的异常安全性的文档(当atomic它们可能泄漏锁时).

结论:

有多种微妙的方法可以解释异常如何破坏东西.很难并且需要深入了解所有相关部分的实现,以在Objective-C中构建异常安全的代码.

所有这些导致了结论.如果要在加载可能已损坏的存档时正常处理错误并在之后继续正常执行:请勿使用NSKeyedArchiver.