据我所知,不鼓励使用@try/@catch块,因为只有在无法恢复的灾难性错误时才会抛出exceptions (请参阅本讨论,并给出@bbum:iOS中的异常处理的一个很好的答案)。
因此,我查看了我的代码,发现了一个不知道如何处理的@try/@catch块:
NSData *fileData = [NSData dataWithContentsOfFile: ....];
NSDictionary *dictionary;
@try {
dictionary = [NSKeyedUnarchiver unarchiveObjectWithData: fileData];
}
@catch (NSException *exception) {
//....
}
@finally {
//...
}问题是(如文档中所述),如果NSData不包含有效存档,则NSData将引发NSInvalidArchiveOperationException。
由于数据是由用户选择的文件提供的,因此不能保证它包含有效的存档,因此如果选择了不正确的文件,应用程序就会崩溃。
现在有两个问题:
+unarchiveObjectWithData:不返回nil (编辑:和NSError**) (这似乎不符合灾难性或不可恢复的错误)。@try)?我没有找到让我们预先检查数据是否包含有效存档的方法,也没有发现使用委托协议处理这种情况的可能性。我忽略了安提兴?请注意,上面的代码当然有效,我只是想知道这是否是最佳实践。
发布于 2013-06-25 15:19:21
NSKeyedArchiver是由苹果制造的。它们控制在unarchiveObjectWithData:执行时执行的代码,因此它们还控制异常处理期间的资源管理(这是Objective中异常背后的麻烦来源)。
如果他们能够保证在您调用unarchiveObjectWithData:和代码中引发异常的点之间没有外部代码(无论是第三方代码还是应用程序代码),理论上就可以安全地使用异常,只要调用代码能够正确地清理。
问题是,这种假设可能不是这样的:使用NSKeyedArchiver来序列化自定义对象是很常见的。通常,自定义类实现initWithCoder:来读取类数据(通过使用归档程序的方法(如decodeObjectForKey:) )。
如果归档程序在这些方法中抛出异常,则无法修复归档程序的资源处理。异常将通过自定义对象的initWithCoder:抛出。归档程序不知道是否有比反序列化对象更多的东西需要清理。因此,在这种情况下,异常的出现意味着进程处于危险状态,可能会导致不必要的行为。
关于你的问题:
为什么NSKeyedArchiver不使用适当的Cocoa错误处理?
只有建立档案的苹果工程师才知道。我的猜测是,异常处理和键控归档是在大致相同的时间(2001年左右)构建的,当时还不清楚异常处理永远不会成为目标C中的头等公民。
@try模式正确吗?
由于上述注意事项的局限性,它是正确的。如果Apple的代码正确地处理异常情况,而您自己的序列化代码也是这样,那么@try模式可能是正确的。
然而,要实现完全正确是非常困难的。您必须确保所有已执行的代码都知道异常并正确地进行清理。
例如,默认情况下,为局部变量和临时对象设置没有例外的清理 (您必须使-fobjc-arc-exceptions能够这样做)。
此外,没有关于@合成属性访问器的异常安全性的文档(当atomic可能泄漏一个锁时)。
结论:
有无数种微妙的方法可以解释异常如何打破某些东西。在Objective中构建异常安全代码是困难的,并且需要深入了解所有相关部分的实现情况。
所有这些都得出了结论。如果您希望在加载可能损坏的档案时优雅地处理错误,然后继续正常执行:不使用
发布于 2015-10-27 23:11:38
iOS 9中添加到NSKeyedUnarchiver中的一个新方法现在返回一个错误:
斯威夫特
public class func unarchiveTopLevelObjectWithData(data: NSData) throws -> AnyObject?目标-C:
+ (nullable id)unarchiveTopLevelObjectWithData:(NSData *)data error:(NSError **)error;但是,这与以前版本的iOS并不是向后兼容的,因此您需要使用检查框架可用性。
https://stackoverflow.com/questions/17299396
复制相似问题