在苹果的并发编程指南中,NSOperation子类示例(包括非并发的和并发的变种)使用异常处理,我想知道他们为什么在操作中鼓励这种风格。
清单2-4响应取消请求
- (void)main {
@try {
BOOL isDone = NO;
while (![self isCancelled] && !isDone) {
// Do some work and set isDone to YES when finished
}
}
@catch(...) {
// Do not rethrow exceptions.
}
}我的理解是,一般来说,异常处理在Objective代码中并不常见--异常本质上是程序员的错误,应该会导致应用程序崩溃,而意外的输入最好由NSError来处理。(我可能误解了这和这之类的东西)
我想知道NSOperations是否呈现了异常处理非常重要的特殊情况,或者这是否更多地是该指南的特定作者的首选样式。
顺便提一下,一些NSOperation示例代码遵循这种风格,而其他示例则不这样做。大多数高可见性操作系统不使用异常(例如,AFNetworking)。
发布于 2012-12-02 17:45:46
您的理解是正确的--应该使用NSError (或类似的)来传递错误信息,而不是异常。大多数目标-C代码并不是例外安全的,并且至少会泄漏资源。一般情况下,不要让你的代码泄露到其他人的代码中--不管是苹果的还是第三方的。一些第三方框架可能明确表示它们是异常安全的,但这是罕见的。
根据这一原则,您可以理解为什么您应该在main方法中使用一个catch异常处理程序。但实际上还有另一个原因:您的操作将在一个专用线程上运行。从操作中抛出的异常将在堆栈上传播,但不会进一步传播。操作的逻辑调用方或所有者不会得到它们,因为它们运行在不同的线程上(或者根本不运行)。因此,泄漏的异常要么会杀死整个程序,要么被默默地吞没,而没有任何其他指示。你的程序可能会陷入一种奇怪的状态--因为你没有意识到一个错误发生了,你可以继续等待你的操作的结果永远不会到来。
此外,苹果在并发编程指南中有一节讨论处理错误和异常。他们关于“离散实体”的第一点暗示了我在上一段中所说的话:
处理错误和异常 因为操作本质上是应用程序中的离散实体,所以它们负责处理出现的任何错误或异常。在OSXv10.6及更高版本中,NSOperation类提供的默认启动方法不会捕获异常。(在OSXv10.5中,start方法确实捕获和抑制异常。)您自己的代码应该始终直接捕获和抑制异常。它还应该检查错误代码,并根据需要通知应用程序的适当部分。如果替换start方法,则必须同样捕获自定义实现中的任何异常,以防止它们离开基础线程的作用域。 在您应该准备处理的错误情况的类型中,有以下几种:
如果您的自定义代码确实遇到异常或错误,则应采取任何必要步骤将该错误传播到应用程序的其他部分。NSOperation类不提供将错误结果代码或异常传递给应用程序其他部分的显式方法。因此,如果这些信息对您的应用程序很重要,则必须提供必要的代码。
发布于 2012-12-02 16:41:01
我认为这个职位和附带的答案很好地阐述了一般的例外-与无例外处理的主题!
在资源无法自动管理的情况下抛出异常是不安全的。Cocoa框架(和邻居框架)就是这样,因为它们使用手动引用计数。 如果您抛出一个异常,您通过解除堆栈而跳过的任何发布调用都会导致泄漏。这应该限制您抛出只有当您确定您不会恢复,因为所有的资源返回到操作系统时,一个进程退出。 不幸的是,NSRunLoops倾向于捕获传播到它们的所有异常,所以如果您在事件期间抛出,您将继续到下一个事件。很明显,这很糟糕。因此,你最好不要扔。 如果使用垃圾收集的object,则此问题将减少,因为由object对象表示的任何资源都将被正确释放。但是,未包装在object对象中的C资源(例如文件描述符或malloc分配的内存)仍然会泄漏。 所以,总之,不要扔。 正如您所提到的,Cocoa有几个解决方案。返回零和NSError**模式是其中的两个。
https://stackoverflow.com/questions/13671028
复制相似问题