在一个 @try-@catch-@finally 块中,是使用 finally 还是正常继续执行好呢?
在一个 @try-@catch-@finally 块中,是使用 finally 还是正常继续执行好呢?
这是一个简单的Objective-C问题。\n当你使用@try
时,工作流程可以以两种方式运行:\n
- \n
- 如果出现某些NSException,代码会立即跳转到
@catch
块,然后到@finally
块。 - 如果没有出现异常,完成运行
@try
块,然后运行@finally
块。
\n
\n
\n那么,使用或者不使用@finally
块有什么区别?如果我只使用:\n
-(void)function{ @try { ... } @catch (NSException *exception) { ... } >>>无论如何,工作流程都将运行这一行? }
\n然后剩余的函数将继续运行,或者只有在创建了NSException时才运行@catch
块?
在一个@try-@catch-@finally块中,使用finally还是正常继续执行的问题的出现原因是因为Apple不推荐在生产代码中使用try/catch语句,因为它们会带来很高的代价,而实际的好处却很少。在C++中,防御性代码随处可见,可以设计应用程序为“基于异常”,这意味着所有代码都设计为堆栈回滚和抛出和重新抛出异常,直到它们达到堆栈的顶层。但是,在Obj-C中并非如此,在C++中,这种范式会破坏大多数编译器优化,因为编译器无法简化任何场景,因为异常可能会在中间中断它。
然而,Apple在Obj-C中提供了try/catch/finally机制,因此您可以创建仅在调试配置中才存在的代码,这将帮助您在将应用程序发布给公众之前发现和捕获错误。
此外,Apple还提供了完整(而美观)的“错误处理”范式和协议,支持API(NSError对象,嵌套的NSErrors NSError恢复协议,NSError显示API等),适用于在应用程序的“发布”版本中处理运行时错误。
所以,关于在生产代码中使用try/catch的整个讨论有点夸大其词。
这是误导性的。在Objective-C中,确实有一些API需要使用try/catch,其中最大的一个是NSTask,如果你哪怕稍微看一眼它,它就会引发一个异常。在某些情况下,某些API不采用传统的NSError方法,这种情况下,您不应该犹豫地使用try/catch来处理Apple的异常类。
因此,根据上述内容,我们可以得出结论,在生产代码中,不推荐使用try/catch语句,而是使用Apple提供的完整的错误处理范式和协议来处理运行时错误。但是,在调试配置中,可以使用try/catch/finally机制来捕获和调试错误。
在一个@try-@catch-@finally块中,使用finally还是正常继续执行,有以下几个要点需要注意:
1. finally块是可选的,可以用来执行无论是否发生异常都必须执行的操作,比如清理。
2. catch块不一定要捕获NSException,可以改为捕获更具体的异常。在这种情况下,finally块和catch块下方的代码将根据异常是否发生而决定是否执行。
3. catch块可以选择处理异常并重新抛出异常或者抛出不同的异常。换句话说,finally块将始终执行,无论catch块中做了什么。
4. 在iOS或Mac OS X开发中,将异常用作可恢复错误是违反系统规范的。如果异常通过系统框架代码的帧抛出,其行为是未定义的。因此,不要使用异常来管理可恢复的错误。
5. 在ARC下,异常默认情况下被编译器认为是不可恢复的。抛出异常(尽管没有进入@catch块)也会导致性能下降。
对于问题的出现原因,可以总结为:
- finally块的作用是在无论是否发生异常的情况下都执行一些必要的操作,比如资源的释放。
- catch块的作用是捕获异常并处理,可以选择重新抛出异常或者抛出不同的异常。
- 异常在iOS或Mac OS X开发中不应用于管理可恢复的错误,使用NSError模式来表示成功或失败。
解决方法如下:
- 对于必须执行的操作,可以将其放在finally块中。
- 对于特定的异常,可以使用更具体的异常类型来捕获。
- 对于可恢复的错误,应使用NSError模式来表示。
以下是整理后的文章:
在一个@try-@catch-@finally块中,我们可以选择使用finally块来执行一些必须在无论是否发生异常的情况下都执行的操作,比如资源的释放。catch块用于捕获异常并进行处理,我们可以选择重新抛出异常或者抛出不同的异常。
需要注意的是,catch块不一定要捕获NSException,我们可以根据具体情况选择更具体的异常类型。然而,无论我们在catch块中做了什么,finally块始终会执行。
另外,需要注意的是,在iOS或Mac OS X开发中,将异常用作可恢复错误是违反系统规范的。如果异常通过系统框架代码的帧抛出,其行为是未定义的。因此,我们不应该使用异常来管理可恢复的错误。
在ARC下,异常默认情况下被编译器认为是不可恢复的。抛出异常(尽管没有进入@catch块)也会导致性能下降。
总结起来,我们应该将必须执行的操作放在finally块中,选择更具体的异常类型来捕获异常,并使用NSError模式来表示可恢复的错误。
需要注意的是,在Mac OS X应用程序中,如果加载插件时发生异常,我们应该如何处理?应用程序应该退出还是尝试恢复?我们可以在插件加载的代码周围使用try-catch块,但是根据系统规范,不应该使用异常来管理可恢复的错误。因此,我们应该使用NSError模式来表示成功或失败。
总之,在@try-@catch-@finally块中,我们可以选择使用finally块来执行一些必须执行的操作,catch块用于捕获异常并进行处理。然而,在iOS或Mac OS X开发中,我们应该避免使用异常来管理可恢复的错误,而应使用NSError模式来表示成功或失败。
在一个@try-@catch-@finally块中,是否使用finally或者正常继续执行,这个问题的出现是因为finally块存在的目的是释放/清理资源,比如打开的套接字、打开的文件、数据库锁、信号量锁等等。如果在catch块内部发生错误或者catch块重新抛出异常,那么行:
>>>The workflow will run this line in any case?
将不会被执行。然而,finally块中的代码应该被执行。finally块是从即将崩溃的应用程序中干净地退出的最后、最好的机会。即使应用程序不会崩溃,它仍然是清理资源的最佳位置,因为与finally块内的代码相比,finally块外的代码更有可能在意外情况下被执行。
是的,在任何try/catch方案中,finally的目的是执行总是需要执行的代码,无论是否发生异常。在Objective-C中,可能是释放对象,在其他上下文中,可能是释放锁或关闭文件。