This week's post is going to be short and simple, and it relates to error handling.
In Objective-C, a common way to report error information to the
caller of a method is to use an NSError
output
argument. For example, here is the declaration of
the writeToFile:options:error
method
on NSData
:
- (BOOL)writeToFile:(NSString *)path options:(NSDataWritingOptions)mask error:(__autoreleasing NSError **)errorPtr;
The method returns a boolean to indicate success or failure. On
failure, a pointer to an NSError
object will be written
to the error
output argument (note the double
stars). All very standard.
What I see too often is code that simply passes
NULL
to the error
argument and doesn't
bother to check the return value. This ignores or hides any errors
that may be generated by the method:
NSData *data = [self makeData];
[data writeToFile:outputFile
options:NSDataWritingAtomic
error:NULL];
In my opinion this is just as bad as gobbling up exceptions in Java:
try { doSomething(); } catch (Throwable e) { }
Swallowing errors like this is very much frowned upon. It can lead
to nightmares in terms of maintainability and debugging, especially
in a language like Objective-C where nil
return values
can go unnoticed and delay the symptoms of an error.
Laziness
I think the reason so many developers fall into this habit is due to laziness. In order to do things properly, you have to declare a new variable, wrap the method you are calling in an if statement, and somehow deal with the error. You may decide you have to pass the error up a level, which would require you to add error feedback to your own interface.
These annoying details crop up when you are already half-way through
writing the method call, so it's almost understandable that people
get frustrated and stuff in a NULL
to get it over and
done with.
It's still wrong, however. And you know it's wrong. So
please, for the sake of professionalism and your fellow developers,
get into the habit of always providing a value to
the error
argument. At the very least you should be
logging the error:
NSData *data = [self makeData]; NSError *error; if (![data writeToFile:outputFile options:NSDataWritingAtomic error:&error]) { MyLogError(@"%@", error); }
I don't even care whether or not you describe what you were doing in
the message. Just stuff a @"%@"
in there and get it
done as quickly as possible. At least the error will
be seen. This is the absolute minimum, and you should do
this for every method call that provides error information.
Even if you are writing quick prototype or test code, I would also suggest you follow this rule. Indeed, these are the situations where you are most likely to make mistakes, and breaking into the debugger to see which method failed is a huge waste of time. It is much faster to write the code properly and get quick feedback on any problems.
Rules are there to be broken
Yes yes, OK. Rules are there to be broken, so what follows is one example where it may (may) be acceptable to ignore an error:
- (void)copySourceFileToDestination { NSString *source = [self sourcePath]; NSString *destination [self destPath]; NSFileManager *manager = [NSFileManager defaultManager]; // Delete/overwrite destination // ignore error because destination might not exist [manager removeItemAtPath:destination error:NULL]; NSError *error; if (![manager copyItemAtPath:source toPath:destination error:&error]) { MyLogError(@"Error copying file: %@", error); // ... } // ... }
In this example we want to copy path source
to destination
, overwriting destination
if
necessary.
The copyItemAtPath:toPath:error:
method will fail
if destination
already exists. To get proper
overwriting behaviour we either have to
implement NSFileManagerDelegate
, or instead (as in this
example) delete destination
first with a call
to removeItemAtPath:error
.
In all likelihood, destination
will not exist, so the
call to removeItemAtPath:error
is going to fail. We
don't care about this particular failure case, so we ignore it. If
anything else does go wrong, we still check the result of
copyItemAtPath:toPath:error:
, so we seem to be in the
clear.
Implementing methods that return errors
I'm going to close this off by giving a little tip for when you write your own methods that return error information.
If somebody calls your code with a NULL
error
value, you want to be as helpful as possible and log the error for
them:
- (BOOL)myAPIMethod:(__autoreleasing NSError **)errorOut { // do some work // ... if (weGotErrors) { if (errorOut) { *errorOut = theErrorWeGot; } else { MyLogError(@"Error doing something: %@", theErrorWeGot); } } // ... }
If we are provided with a non-NULL output argument, we write out the error and it is up to the caller to log, handle or ignore the error as they wish.
If we are given NULL
, we're going to assume the
developer is lazy and log the error for them. If
they really want to ignore the error, they can provide an
output argument and do the ignoring in their own
code. In our code we are going to be responsible developers
and make sure errors are visible by default.
Be responsible
Things can get tedious in Objective-C. Error handing can be annoying and can make an already ugly block of code even uglier. But stay true to your core values, be responsible, and put in that extra bit of effort to write robust and programmer-friendly code.
That's the end. Thanks for reading.
I suggest you to to initialize the NSError *error variable to nil, in my experience can happens that the error variable has garbage value. In your case this isn't a problem because the function return a BOOL indicating that an error occurred but this isn't always true , so if you check error == nil and you have garbage value in it this check can be false even if no error occurs.
ReplyDeleteAwesome article, glad I ran across it !!! I'm definately going to check out the WWDC video. Much thanks again ;-) score +1 for the kitten.دانلود آهنگ های ایرانی
DeleteIn Objective-C, encountering an error related to null typically involves issues with handling pointers or objects that are uninitialized or have been explicitly set to nil. Here are some common scenarios and solutions:
DeleteIn Objective-C, null is typically represented by nil, which is a pointer to a non-existent object or a null pointer. When you encounter an error related to null, it often means that you are trying to access or manipulate an object that hasn't been properly initialized or has been explicitly set to nil.
final year projects for computer science
Final Year Project Centers in Chennai
IEEE projects for cse
IMO every method that takes a NSError** as an output parameter should allow to check if there is any error by its return value. Is like that in all libraries I have dealt with. Anyway I also set the NSError *error to nil before passing it.
ReplyDeleteThanks for giving me the push I needed. I was just about to give up trying to find the proper way to handle errors in my case for a personal project, but I'm going to find a way to make it work.
ReplyDelete@Luca Bernardi You honestly don't even need to check if error is nil. Just check:
ReplyDeleteif (error) { };
if a variable is nil, it will return a logical FALSE when tested, otherwise it will always return TRUE
@Luca Bernardi You honestly don't even need to check if error is nil. Just check:
ReplyDeleteif (error) { };
if a variable is nil, it will return a logical FALSE when tested, otherwise it will always return TRUE
iPhone APP Development Company Dublin CA is saying its an informative article. Good job!
ReplyDeletewww.krogerfeedbackz.info comments required.
ReplyDeleteFaisalabad is one of the biggest cities in Pakistan and the hub of the textile industry. It is widely acknowledged as the Manchester of Pakistan due to its large industrial role. The quality of the fabrics produced in this city has no parallel. In fact, the fabric is something of a specialty of Faisalabad. Many people from all over the country flock to this city for a spot of cloth shopping. We aim to provide you all of the best of Faisalabad at our store.pakistani wholesale salwar kameez , pakistani wholesale salwar kameez
ReplyDeleteIn the world of product engineering, few manufacturing options are as dependable and practical as CNC machining. Through its a long time of development, it’s come a good distance and adapted to serve the wants of broad variety|all kinds} of projects. At the identical time, our experienced engineers ensure the best standards with cutting edge software program and equipment. The excessive dimensional accuracy of CNC machining comes into play Direct CNC with robotics; robots have to be correct of their movements and positioning.
ReplyDelete