In a #try-#catch-#finally block, is it good use finally or to continue normally? - objective-c

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?

"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.

A couple things to note:
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
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

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.

Related

Can .NET SqlConnection.Dispose() throw an exception?

Is it possible for the Dispose method of a SqlConnnection object to throw an exception? It's always shown sitting on its own in a finally block outside of the try-catch. And if a using block is equivalent to a try...finally which then calls Dispose, that would also seem to be a case when an exception thrown by Dispose would be problematic.
Technically it can, but it shouldn't:
CA1065: Do not raise exceptions in unexpected locations :
A IDisposable.Dispose method should not throw an exception. Dispose is often called as part of the clean up logic in a finally clause. Therefore, explicitly throwing an exception from Dispose forces the user to add exception handling inside the finally clause.
The Dispose(false) code path should never throw exceptions, because this is almost always called from a finalizer.
Dispose Dos and Don'ts:
Don't throw exceptions in Dispose. Nothing should go wrong with your object calling Dispose.
The moral of the story appears to be that an exception thrown from Dispose is a very bad thing (for some of the reasons you mentioned) and should be handled as high as possible (there's nothing you can do about it, and probably can't recover from it).
In general, a block of code should finish normally if the state of the system will match what the surrounding code expects, and throw an exception if it won't. The the try/catch/finally construct in .NET has a weakness, however, which flows into the IDisposable interface which is designed to work with it (via language constructs like using): a method
void Test()
{
try
{
doSomething();
}
finally
{
doCleanup();
}
}
should only exit normally if both doSomething() and doCleanup() succeed, but if doSomething() throws an exception, the Test() method as a whole should either throw that exception or make it possible to log it. Meeting both requirements would require either that doCleanup() throw an exception of it runs following a successful call to doSomething(), but not following a call which threw an exception, or else that any exception it throws incorporates information about the exception thrown from doSomething().
Unfortunately, there is no convenient way of writing a finally block to vary its behavior based upon the result of the try , nor is there any way for a Dispose() method invoked from a finally to do so. Thus, it is necessary for Dispose implementations to try to guess whether it's more evil to exit normally when an operation fails, or throw an exception which may overwrite an earlier one that held useful information. The latter is somewhat evil, but often not as evil as the former.
For example, consider the pseudocode:
RenameFile(mainFileName, backupFileName);
using(outFile = File.Create(mainFileName);
{
writeDataToNewFile(outFile);
}
DeleteFile(backupFileName);
If something goes wrong while closing the output file and the exception gets propagated out of the using block, the backup file will be left intact and might be recovered later. If the using block were allowed to complete normally despite a failure which prevented the main file from being properly written, the backup file would get deleted, possibly destroying the only copy of some of the data contained therein.
The idea that Dispose shouldn't throw exceptions relates to the fact that there's often no good way to handle exceptions thrown from Dispose. The bigger problem, however, is that there's no good way of handling problems that arise during Dispose without knowing the circumstances under which it is invoked. Throwing an exception from Dispose may be somewhat evil, but still be less evil than allowing it to complete normally in cases where real problems exist.

How to use the "All Exceptions" breakpoint for exceptions outside #try {} #catch {}?

In Xcode, you can go to the Breakpoints tab, then add a breakpoint for "All Exceptions".
I find this very helpful, but is it possible for this to break the program only when the exception is not handled by a #try {} #catch {} in my code? Those are the only ones that interest me.
It would be even nicer if I could select specific files where I'm interested in using this breakpoint system, although I'm guessing that's a bit too much to ask.
The best I've found is breaking on abort; it will print the exception and backtrace in the log before breaking. You may also have luck setting your own unhandled exception handler and breaking on that.
If you really want to use All Exceptions the way you described, please file a bug with apple:
http://bugreport.apple.com

NSKeyedUnarchiver - try/catch needed?

As I understand, the use of #try/#catch blocks is discouraged, because exceptions should only be thrown at unrecoverable, catastrophic errors (refer to this discussion with a nice answer by #bbum: Exception Handeling in iOS).
So I looked through my code and found a #try/#catch block that I don't know how to get rid of:
NSData *fileData = [NSData dataWithContentsOfFile: ....];
NSDictionary *dictionary;
#try {
dictionary = [NSKeyedUnarchiver unarchiveObjectWithData: fileData];
}
#catch (NSException *exception) {
//....
}
#finally {
//...
}
The problem is that (as stated in the documentation) +unarchiveObjectWithData: raises an NSInvalidArchiveOperationException if the NSData doesn't contain a valid archive.
Since the data is provided by a file the user chose, it is not guaranteed that it contains a valid archive, and thus the application would crash if a incorrect file was chosen.
Now two questions:
Why doesnt +unarchiveObjectWithData: just return nil (Edit: and an NSError**) if the archive is not valid (this doesn't seem to qualify as a catastrophic or unrecoverable error).
Is the pattern above correct (using #try)? I have found no method that lets us check if the data contains a valid archive beforehand and have found no possibility to handle this case using the delegate protocol. Antyhing I overlooked?
Note that the code above of course works, I just wonder if its the best practice.
There was a new method added in iOS 9 to NSKeyedUnarchiver that now returns an error:
Swift:
public class func unarchiveTopLevelObjectWithData(data: NSData) throws -> AnyObject?
Objective-C:
+ (nullable id)unarchiveTopLevelObjectWithData:(NSData *)data error:(NSError **)error;
However, this is not backwards compatible with previous versions of iOS, so you will need to check for framework availability.
NSKeyedArchiver is built by Apple. They control the code that is performed while unarchiveObjectWithData: executes so they also control resource management during exception handling (which is the source of trouble behind exceptions in Objective-C).
If they can guarantee that in between your call to unarchiveObjectWithData: and the point in code where they raise the exception is no foreign code (neither third party nor your app's code) it is in theory possible to safely use an exception, as long as calling code takes care of cleaning up correctly.
The problem is that this assumption might not be the case: It is common to use NSKeyedArchiver to serialize custom objects. Usually the custom class implements initWithCoder: to read the classes data (by using the archiver's methods like decodeObjectForKey:).
If the archiver throws an exception in one of these methods there's no way to fix resource handling for the archiver. The exception will be thrown through the custom object's initWithCoder:. The archiver does not know if there's more stuff to clean up than the deserialized objects. So in this scenario the occurrence of the exception means that the process is in a dangerous state and unwanted behavior may result.
Regarding your questions:
Why doesn't [NSKeyedArchiver use proper Cocoa error handling]?
Only the Apple engineers who built the archiver know. My guess is that exception handling and keyed archiving were built at roughly the same time (around 2001) and at that point it wasn't yet clear that exception handling would never be a first class citizen in Objective-C.
Is the #try pattern correct?
With the limitation of the caveats described above it is correct. If Apple's code handles the exception cases properly and your own serialization code does the same the #try pattern might be correct.
It is very difficult to achieve full correctness, though. You'd have to make sure all executed code is aware of the exceptions and does cleanup correctly.
ARC, for instance, does no exception cleanup for local variables and temporary objects by default (you would have to enable -fobjc-arc-exceptions to do this).
Also, there's no documentation on exception safety of the accessors of #synthesized properties (when atomic they might leak a lock).
Conclusion:
There are a myriad of subtle ways of how exceptions can break stuff. It is difficult and requires in depth knowledge of the implementation of all involved parts to build exception safe code in Objective-C.
All this leads to the conclusion. If you want to handle errors gracefully while loading possibly corrupted archives and continue normal execution afterwards: Do not use NSKeyedArchiver.

Why does NSOperation example code uses #try & #catch

In Apple's Concurrency Programming Guide the NSOperation subclass examples (both non-concurrent and concurrent varieties) use exception handling and I'm wondering why they are encouraging this style within operations.
Listing 2-4 Responding to a cancellation request
- (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.
}
}
My understanding is that generally exception handling is not a common practice in Objective-C code - exceptions are essentially programmer errors and should cause the app to crash whereas unexpected inputs are best handled by NSError. (My possibly misinformed understanding comes from things like this and this)
I'm wondering if NSOperations present a particular situation in which exception handling is important, or if this is more the preferred style of the particular author of that guide.
As a side note, some of the NSOperation example code follows this style, other examples do not. Most high-visibility OSS does not use exceptions (AFNetworking, for example).
Your understanding is correct - NSError (or similar) should be used to convey error information, rather than exceptions. Most Objective-C code is not exception-safe and will at the very least leak resources. As a general rule, never let your code leak an exception into anyone else's code - whether Apple's or a 3rd parties. Some 3rd party frameworks may explicitly indicate they are exception safe, but it's rare.
By that principle you can see why you should have a catch-all exception handler in your main method regardless. But there's actually another reason: your operation will be run on a dedicated thread. Exceptions thrown from your operation will propagate up the stack, but no further. The logical caller or owner of the operation won't get them, as they're running on a different thread (or not at all). So leaked exceptions will either kill your whole program, or be swallowed silently with no other indication. Your program may then get stuck in a weird state - since you didn't realise an error occurred, you may continue waiting for the result of your operation that will never arrive.
Additionally, Apple has a section in the Concurrency Programming Guide where they talk about Handling Errors and Exceptions. Their first point on "discrete entities" is alluding to what I said in the previous paragraph:
Handling Errors and Exceptions
Because operations are essentially
discrete entities inside your application, they are responsible for
handling any errors or exceptions that arise. In OS X v10.6 and later,
the default start method provided by the NSOperation class does not
catch exceptions. (In OS X v10.5, the start method does catch and
suppress exceptions.) Your own code should always catch and suppress
exceptions directly. It should also check error codes and notify the
appropriate parts of your application as needed. And if you replace
the start method, you must similarly catch any exceptions in your
custom implementation to prevent them from leaving the scope of the
underlying thread.
Among the types of error situations you should be prepared to handle
are the following:
Check and handle UNIX errno-style error codes.
Check explicit error
codes returned by methods and functions.
Catch exceptions thrown by
your own code or by other system frameworks.
Catch exceptions thrown
by the NSOperation class itself, which throws exceptions in the
following situations:
When the operation is not ready to execute but
its start method is called
When the operation is executing or finished
(possibly because it was canceled) and its start method is called
again
When you try to add a completion block to an operation that is
already executing or finished
When you try to retrieve the result of
an NSInvocationOperation object that was canceled
If your custom code
does encounter an exception or error, you should take whatever steps
are needed to propagate that error to the rest of your application.
The NSOperation class does not provide explicit methods for passing
along error result codes or exceptions to other parts of your
application. Therefore, if such information is important to your
application, you must provide the necessary code.
I think this post and the accompanying answer elaborates very well on the general exception- vs. no exception handling topic!
It is unsafe to throw exceptions in circumstances where resources are
not automatically managed. This is the case of the Cocoa framework
(and neighbor frameworks), as they use manual reference counting.
If you throw an exception, any release call you skip over by unwinding
the stack will result in a leak. This should limit you tothrowing only
if you're certain that you're not going to recover since all resources
are returned to the OS when a process quits.
Unfortunately, NSRunLoops tend to catch all exceptions that propagate
to them, so if you throw during an event, you'll resume to the next
event. This is, obviously, very bad. Therefore, it's better that you
simply don't throw.
This problem is diminished if you use garbage-collected Objective-C,
as any resource represented by an Objective-C object will be properly
released. However, C resources (such as file descriptors or
malloc-allocated memory) that are not wrapped in an Objective-C object
will still leak.
So, all in all, don't throw.
The Cocoa API has several workarounds to this, as you mentioned.
Returning nil and the NSError** pattern are two of them.

Using Exception Handling versus NSError in Cocoa Apps

Hey all. I've been reading up on Apple's suggestions for when/where/how to use NSError versus #try/#catch/#finally. Essentially, my impression is that Apple thinks it best to avoid the use of exception handling language constructs except as a mechanism for halting program execution in unexpected error situations (maybe someone could give an example of such a situation?)
I come from Java, where exceptions are the way to go when one wants to handle errors. Admittedly, I'm still in the Java thoughtspace, but I'm slowly coming to grips with all that NSError has to offer.
One thing I'm hung up on is the task of cleaning up memory when an error occurs. In many situations (e.g. using C, C++ libraries, CoreFoundation, etc..) you have a lot of memory cleanup that needs to be done before breaking out of a function due to an error.
Here's an example I cooked up that accurately reflects the situations I've been encountering. Using some imaginary data structures, the function opens up a file handle and creates a 'MyFileRefInfo' object which contains information about what to do with the file. Some stuff is done with the file before the file handle is closed and the memory for the struct freed. Using Apple's suggestions I have this method:
- (BOOL)doSomeThingsWithFile:(NSURL *)filePath error:(NSError **)error
{
MyFileReference inFile; // Lets say this is a CF struct that opens a file reference
MyFileRefInfo *fileInfo = new MyFileRefInfo(...some init parameters...);
OSStatus err = OpenFileReference((CFURLRef)filePath ,&inFile);
if(err != NoErr)
{
*error = [NSError errorWithDomain:#"myDomain" code:99 userInfo:nil];
delete fileInfo;
return NO;
}
err = DoSomeStuffWithTheFileAndInfo(inFile,fileInfo);
if(err != NoErr)
{
*error = [NSError errorWithDomain:#"myDomain" code:100 userInfo:nil];
CloseFileHandle(inFile); // if we don't do this bad things happen
delete fileInfo;
return NO;
}
err = DoSomeOtherStuffWithTheFile(inFile,fileInfo);
if(err != NoErr)
{
*error = [NSError errorWithDomain:#"myDomain" code:101 userInfo:nil];
CloseFileHandle(inFile); // if we don't do this bad things happen
delete fileInfo;
return NO;
}
CloseFileHandle(inFile);
delete fileInfo;
return YES;
}
Now.. my Java logic tells me that it would be better to set this up as a try/catch/finally structure and put all the calls to close the file handle and free memory in the finally block.
Like so..
...
#try
{
OSStatus err = OpenFileReference((CFURLRef)filePath ,&inFile);
if(err != NoErr)
{
... throw some exception complete with error code and description ...
}
err = DoSomeStuffWithTheFileAndInfo(inFile,fileInfo);
if(err != NoErr)
{
... throw some exception ...
}
... etc ...
}
#catch(MyException *ex)
{
*error = [NSError errorWithDomain:#"myDomain" code:[ex errorCode] userInfo:nil];
return NO;
}
#finally
{
CloseFileHandle(inFile); // if we don't do this bad things happen
delete fileInfo;
}
return YES;
Am I crazy in thinking that this is a much more elegant solution with less redundant code?
Did I miss something?
Daniel's answer is correct, but this question deserves a rather more blunt answer.
Throw an exception only when a non-recoverable error is encountered.
Use NSError when communicating error conditions that may be recovered from.
Any exception that is thrown through a frame in Apple's frameworks may result in undefined behavior.
There is an Exceptions programming topic document available in the dev center.
Essentially, my impression is that Apple thinks it best to avoid the use of exception handling language constructs except as a mechanism for halting program execution in unexpected error situations (maybe someone could give an example of such a situation?)
That's not quite my impression. I thought that Apple suggests using exceptions for truly exceptional conditions, and NSError for expected failures. Since you come from Java, I think NSError -> java.lang.Exception, and Obj-C Exceptions -> java.lang.RuntimeException. Use an Obj-C exception when the programmer did something wrong (used an API incorrectly, for example), and use NSError when an expected failure occurred (the remote server could not be found, for example).
Of course, that's just my interpretation of Apple's position. I, on the other hand, like exceptions!
Exceptions in Objective-C have historically been 'heavy', with a performance cost to entering a try block, a cost to throwing, a cost to using finally, etc. As a result Cocoa developers have typically avoided exceptions outside of 'oh no, the sky is falling' sorts of situations -- if a file is missing, use an NSError, but if there's no filesystem and a negative amount of free memory, that's an exception.
That's the historical view. But if you're building a 64-bit app on 10.5 or newer, the exception architecture has been rewritten to be 'zero cost', which may mean that the historical view is no longer relevant. As with just about anything, it comes down to various factors -- if working one way is more natural to you and will let you finish more quickly, and if you don't experience any performance-related problems with it, and if being slightly inconsistent with 'traditional' Objective-C code doesn't bother you... then there's no reason not to use exceptions.
According to More iPhone 3 Development by Dave Mark and Jeff LeMarche, exceptions in are used only for truly exceptional situations and usually indicate a problem within your code. You should never use exceptions to report a run-of-the-mill error condition. Exceptions are used with much less frequency in Objective-C than in many other languages, such as Java and C++.
You use an exception when you need to catch a mistake in your code. You use an error when the user may need to fix the problem.
Here's an example where you would use an exception:
We're writing a superclass, and we want to make sure its subclasses implement a given method. Objective-C doesn't have abstract classes, and it lacks a mechanism to force a subclass to implement a given method. Yet we can use an exception to instantly inform us that we forgot to implement the method in a subclass. Instead of an unpredictable behavior, we'll get slammed with a runtime exception. We can easily debug it because our exception will tell us exactly what we did wrong:
NSException *ex = [NSException exceptionWithName:#"Abstract Method Not Overridden" reason:NSLocalizedString(#"You MUST override the save method", #"You MUST override the save method") userInfo:nil];
[ex raise];
Because problem is a programmer mistake rather than a problem the user may be able to fix, we use an exception.