I\'m coding up various routines and I\'m trying my best to keep it neat and refactored.
Methods I\'m creating are starting to look similar to this code:
Note: When I posted this I was unaware of any MacOS/Cocoa exceptions debate. Please bear this in mind when you consider this answer.
Why not use exceptions instead? This will allow you to dispense with the error parameter on your methods and handle your errors in one place.
-(IBAction)buttonPress:(id)sender {
// Create Document Shopping List with this document
@try {
[self doSomething];
[self doSomethingElse];
[self doYetSomethingElse];
} @catch (NSException* e) {
[NSApp presentException:e];
}
return nil;
}
You will of course need to throw exceptions as required from within your doXXXX methods:
NSException* e = [NSException exceptionWithName:@"MyException"
reason:@"Something bad happened"
userInfo:nil];
@throw e;
I think the real question is how much granularity you need in your error handling. Your code is fundamentally correct - but you can clean things up by checking for errors less frequently, or using a catch-all approach like teabot mentioned in his answer with NSException. A lot of the built-in functions that return errors (like NSFileManager's moveItemAtPath:) return a BOOL in addition to a providing an NSError object - so you could also use nested if statements if you don't need the NSError information.
All and all though, there's really not a great way to do this. If your code is long, KVO might be a cool solution. I've never tried it for a situation like this, though.
I think that none of the answers presented here are taking into account Apple's recommended practices.
Basically you should never check for the NSError
object to determine if there was a problem. You check if there was a problem by checking the value returned from the method that takes a pointer to a pointer to an NSError
.
From the Apple documentation:
Important Success or failure is indicated by the return value of the method. Although Cocoa methods that indirectly return error objects in the Cocoa error domain are guaranteed to return such objects if the method indicates failure by directly returning
nil
orNO
, you should always check that the return value isnil
orNO
before attempting to do anything with theNSError
object.
The gist of your question is whether there are structural improvements you can make to your error handling. I think so, by essentially introducing more layers of nesting, either by extracting more code into separate methods/functions, or by introducing nesting in your high level sample method.
The idea is, when it comes to handling most errors, you probably are either interested in performing an alternate task, or in failing and propagating the error up the chain so that some responsible controller can convey the error to the user through UI.
Using this idea of "propagate or handle", I would rewrite your sample method like this:
-(IBAction)buttonPress:(id)sender {
// Create Document Shopping List with this document
[self doSomething:&error];
if(error == nil) {
[self doSomethingElse:&error];
if (error == nil) {
[self doYetSomethingElse:&error];
}
}
if(error) {
[NSApp presentError:&error];
}
}
Note that there are good arguments against introducing too much nesting in a particular method. Nesting such as this is essentially a short alternative to extracting methods. It might make more sense, for instance, that "doSomething:" itself calls doSomethingElse:, which calls doYetSomethingElse: for instance. This would impose the same structure on the code as the if-nest, but would be arguably more maintainable.
As an aside, I am not a fan of inline return statements. In this particular instance, the sample method doesn't actually call for a return value, but if it did, I prefer to set a local variable to the returned value and only return at the end of the flow control. Jumping out of a function or method prematurely is a sure way to encounter weird bugs, IMHO.