19

This is a simple Objective-C question.

When you use a @trythe work flow can run in 2 ways

  • If some NSException appear, the code immediately jump to @catch block and than to @finally
  • If not, finish to run the @try block and than run @finally

So, what is the difference to use or not use the @finally block? If I use only:

-(void)function{
    @try {
     ...
    }
    @catch (NSException *exception) {
     ...
    }
    >>>The workflow will run this line in any case?
}

Than the rest of the function will run, or only the @catch block if a NSException is created?

Vvk
  • 4,031
  • 29
  • 51
Rodrigo
  • 11,909
  • 23
  • 68
  • 101
  • See http://stackoverflow.com/questions/547791/why-use-finally-in-c . Not objective-c related per se, but I assume it works the same: Sometimes your catch block will want to break out of the flow, this is when you want a finally block to run whether or not the rest of the function will continue. – Rotem Jan 11 '12 at 14:04

3 Answers3

18

"A @finally block contains code that must be executed whether an exception is thrown or not." Does code in finally get run after a return in Objective-C?

The finally block exists to release/clean up resources like open sockets, open files, database locks, semaphore locks, and so on.

If an error occurs inside of the catch block or the catch block rethrows the exception, then the line:

>>>The workflow will run this line in any case?

is not executed. However, the code in the finally block should be executed. The finally block is the last, best chance to exit cleanly from an application that is about to crash. Even if the application is not about to crash, it is still the best place to cleanup resources because the code inside the finally block is more likely to be executed under unexpected conditions than code outside of the finally block.

Community
  • 1
  • 1
ahoffer
  • 6,347
  • 4
  • 39
  • 68
  • Yeah, the purpose of `finally`, in any try/catch scheme, is to execute code that needs to always be executed, whether an exception occurs or not. In Objective-C this might be releasing an object, in another context it might be releasing a lock or closing a file. – Hot Licks Jan 12 '12 at 01:07
4

A couple things to note:

  1. The @catch block is not required, you can have @try-@finally, and use the @finally block for anything (e.g. cleanup) that must happen even if an exception occurs
  2. The @catch block doesn't have to catch NSException, it may (and probably should) be changed to catch more specific exceptions. In that case the @catch block, along with the code below the @try-@catch-@finally, would not be run depending on the exception
Nathanial Woolls
  • 5,231
  • 24
  • 32
  • Also, 3. the catch block may choose to do some processing and rethrow the exception or throw a different exception. – JeremyP Jan 11 '12 at 14:50
  • In other words, @finally will always run regardless of what is done in the catch block. – Mike D Jan 11 '12 at 15:27
  • 3
    4. Any use of exceptions as recoverable errors in iOS or Mac OS X development is in violation of the patterns set forth by the system. If an exception is thrown through a frame of the system framework code, the behavior is undefined. I.e. **do not use exceptions for management of recoverable errors**. – bbum Jan 11 '12 at 18:15
  • 2
    bbum's point is especially important under ARC, where exceptions are *expected by the compiler* to not be recoverable by default. Throwing an exception (although not entering an @try block) is also quite slow. – Catfish_Man Jan 11 '12 at 18:18
  • @bbum: What if say, you were building a Mac OS X application that had an extendible system that utilises 3rd-party bundles, and while loading the bundle, an exception was thrown; what should happen? Should the application quit, or should it try to recover? Presumably the application would put `@try`/`@finally` around the bundle loading, but are you saying it shouldn't be used for this? – dreamlax Jan 12 '12 at 00:45
  • @bbum It'd be nice if the docs actually said that. There are some notes about avoiding exceptions for general flow control, but nothing as strong as what you've said here. More generally, it'd be nice if exceptions became *more* useable with each version rather than *less*... they are a documented feature of the language, after all. I'm sure there are good reasons, but still... – Caleb Jan 12 '12 at 01:37
  • Exceptions are fatal; end of story. The "Introduction to Exception Programming Topics for Cocoa" contains a succinct description of the design pattern employed. @Caleb Many of us -- oft through years of experience of using both exception-heavy and exception-unfriendly systems -- have come to the conclusions that exception based programming is untenable. The Cocoa frameworks are designed with this principal and changing it would be difficult. Clearly, a better pattern than NSError could be used, but at least NSError isn't a stack based GOTO like exceptions. – bbum Jan 12 '12 at 05:22
  • @dreamlax Same rules apply for plug-in systems. A properly written plug-in system will have some kind of initialization or registration phase and that should use the `NSError` pattern to indicate success/failure. Exceptions are reserved for unrecoverable errors. – bbum Jan 12 '12 at 05:28
  • @bbum "exception based programming is untenable" How this relates to Swift? What makes the difference that it is tenable in Swift now? Sorry for hijacking the thread, but I feel the discussion could continue here... I just landed on a lib in objc project, which throws exceptions instead of errors, and found this very interesting conversation. After almost 6 years of objc programming it is the first time I am forced to use try-catch in objc... – Vilém Kurz Jun 27 '16 at 13:32
3

Few important points that were missed in other's answers here.

  • Apple does NOT recommend the use of @try @catch @finally clauses in production code. Their penalty is too high, and the real benefits are few. In C++ where defensive code is all over the place, you can design your application to be "exception based" meaning, all the code is designed for stack-rollback and throwing and rethrowing exceptions until they reach the top level of the stack. This is NOT the case in Obj-C, and even in C++ this paradigm kills most compiler optimizations, because the compiler cannot shortcut any scenario as an exception can break it in the middle.
  • However --- Apple provides the try/catch/finally mechanism in Obj-C, so you can create debug-configuration-only code, that will help you identify and catch (literally) your bugs BEFORE releasing the application to the public.
  • In addition Apple provides a complete (and beautiful) "Error handling" paradigm and protocol, backed up in API (NSError object, nested NSErrors NSError recovery protocol, NSError display API etc.) that is suitable for runtime error handling in your application - in "release" builds of your applications.
  • The above is correct for both iOS and MacOS-X error handling.

So, the whole discussion about the use of @finally here are a little exaggerated.

Motti Shneor
  • 2,095
  • 1
  • 18
  • 24
  • 1
    Good points.. Can can you give me the pointer to these points, does apple officially says so? – riyaz Apr 21 '16 at 08:16
  • 4
    Can you provide a link to documentation where Apple says that try/catch is not recommended in production code? I can't find any. – manmal Aug 11 '16 at 11:03
  • This is misleading. There are certainly APIs that warrant the use of try/catch, even in Objective-C. The biggest one that comes to mind is NSTask, which will raise an exception if you even look at it funny. There are certain APIs that don't adopt the traditional NSError approach, and in those cases you should not be hesitant to use try/catch to deal with Apple's exception-happy classes. – Bryan Dec 08 '18 at 01:17