In Cocoa, when should I use NSAssert, NSException, NSError?
Here's what I've been thinking:
NSAssert - When creating any client program used for the programmers own benefit to double check rules, conventions, assumptions, or pre-conditions and post-conditions?
NSException - When creating a third-party library for the benefit of other programmers that use the library, so that they immediately know when an input is invalid?
NSError - When interfacing with an external system to get data like a file, database, or web service that isn't guaranteed to give me a result?
An NSAssert will throw an exception when it fails. So NSAssert is there to be short and easy way to write and to check any assumptions you have made in your code. It is not (in my opinion) an alternative to exceptions, just a shortcut. If an assertion fails then something has gone terribly wrong in your code and the program should not continue.
One thing to note is that NSAssert will not be compiled into your code in a release build, so this is typically used for sanity checking during development. I actually tend to use a custom assert macro that is always active.
The times you would #throw your own NSException are when you definitely want it in a release build, and in things like public libraries/interface when some arguments are invalid or you have been called incorrectly. Note that it isn't really standard practice to #catch an exception and continue running your application. If you try this with some of Apple's standard libraries (for example Core Data) bad things can happen. Similar to an assert, if an exception is thrown the app should generally terminate fairly quickly because it means there is a programming error somewhere.
NSErrors should be used in your libraries/interfaces for errors that are not programming errors, and that can be recovered from. You can provide information/error codes to the caller and they can handle the error cleanly, alert the user if appropriate, and continue execution. This would typically be for things like a File-not-found error or some other non-fatal error.
The convention in Cocoa is that an exception indicates a programmer error. A lot of code, including framework code, is not designed to work properly after an exception is thrown.
Any sort of error that should be recoverable is represented by an NSError. There’s also a system for presenting NSErrors to the user. As you say, this is mostly useful for fallible external resources.
Conceptually, an assertion is a statement that a given predicate always evaluates to true; if it doesn’t, the program is broken. While its behaviour can be modified, the NSAssert family is by default a convenient way of throwing NSInternalInconsistencyExceptions (with the option of turning them off in release builds).
Edit:
In Xcode 4.2, assertions are turned off by default for release builds,
Now NSAssert will not be compiled into your code in a release build, but you can change it in build settings
#Mike Weller, There are one wrong in your answer.
One thing to note is that NSAssert will not be compiled into your code in a release build, so this is typically used for sanity checking during development.
Actually, NSAssert will be compiled into your code if you don't add NS_BLOCK_ASSERTIONS in your precompiled prefix files.
In Technical Note TN2190 we can find:
Macros like NDEBUG to turn off C assert or NS_BLOCK_ASSERTIONS to turn off Foundation's NSAssert are important to specify for your precompiled prefix files
Or you can read this one:How to know if NSAssert is disabled in release builds?
In general, exceptions are used to signal programmer errors — they're things that shouldn't happen. Errors are used to signal error conditions that might come up in the normal operation of the program — user errors, basically, or external conditions that need to be true but might not be. So trying to delete some locked element in a document might be an error, and trying to download a file without an Internet connection would be an error, but trying to access an invalid element in a collection would be an exception.
Assertions are typically used in testing, and AFAIK are not used as a general error-handling mechanism like the others.
Related
I'm invoking a small AppleScript handler from within a larger Cocoa/Objective-C app (using the AppleScript-ObjC framework to call the AppleScript methods directly from the Objective-C code). I originally tried using Scripting Bridge, but that didn't work for me due to compatibility problems with the external app. The only purpose of the AppleScript is essentially to send a small string to the external app. This is the first time I've attempted to do something like this in order to control an external application, so please bear with me if I'm making an obvious mistake.
Occasionally, the AppleScript may encounter errors depending on the state of the external application, and I would like to handle those errors appropriately in my Objective-C code.
The way I'm doing this right now is that I have a try block in the AppleScript:
try
-- Do stuff
return the number 0
on error the error_message number the error_number
return the error_number
end try
I return zero if the script finishes normally, and return the error number if it doesn't. Then in the Objective-C code, I test the return value and throw a "normal" exception in cases where there is an error, so that I can handle that in my regular exception-handling code.
This works, but is there a way to trap the AppleScript exception directly from the Objective-C code? When I run the code without the AppleScript try-error code in XCode, it seems that it hits my exception breakpoint before it returns from the AppleScript, but it never invokes the #catch block for NSException. Is there some way to catch that exception that is being hit somehow? I'm guessing the answer is no, but I wanted to check that there isn't some better way to do this than what I'm doing. Apple's documentation on AppleScript-ObjC is rather sparse, and mostly just discusses handling errors within AppleScript.
Update:
So, I just tried playing around with the breakpoint setup a little bit, and it turns out that it's a C++ exception being sent from the AppleScript code, not an Objective-C one. That's why it wasn't being caught by the #catch block I was using. It seems that the AppleScript-ObjC mechanism uses exceptions for control flow/recoverable errors, and I had my breakpoint set up to break when they are thrown. So, I think it's probably best to just catch the errors in the AppleScript application, and return an error code as a string or integer to the Objective-C code.
AppleScript uses C++ exceptions to implement its own exceptions, but nothing else; you shouldn’t see them in code that completes successfully. If an AppleScript exception escapes to point of returning to Objective-C, the bridge actually swallows it -- you should get a log message, and a nil/zero/NO return value from the bridged method. The upshot of all this is that you’re already doing the right thing: trap the error in AppleScript and return something that your Objective-C code can detect.
As a side note, AppleScriptObjC is mainly intended for developers writing applications primarily or entirely in AppleScript. If you’re writing a primarily Objective-C application with a few bits that control other applications via scripting, consider using ScriptingBridge instead.
As a developer with java background I am used to often catching exceptions to prevent them from crashing my app. This includes all kinds of delegate methods. Just an extra safety measure for unexpected situations.
My question is whether such approach is sensible in objective c and does it introduce some sort of performance problems? I other words would my app suffer in any way if I use try/catch blocks more often?
It won't suffer that much, but you have to remember something. Unlike in other languages where you might have ConnectionRefusedException or FileNonexistantException, in objective-c, exceptions are programmer errors 90% of the time. So by the time your app enters production, it shouldn't have any exceptions anyway. Rather than, for example, catching out of bounds exceptions, just look at array length before trying. You can make a top level try-catch though just in case that gives the error and exits more gracefully than a crash.
In general, you don’t want exceptions to occur while your program is running. So it’s considered better programming practice to test for errors before they occur rather than to catch them after they occur.
It’s also better to test for an error in a method and return some value as an error indicator than to throw an exception.Throwing exceptions use a lot of system resources, and, as such,
Apple generally recommends against using their unnecessary use (e.g., you don’t want to throw an exception simply because you can’t open a file).
Well the best practice is that you use try and catch only when you are loading data, modules, files and things that might not work due to user environment settings or user submitted data.
An exception is an exception, and should not be happening that often : )), so it won't affect performance at all.
Usually protocols contain delegate methods for both normal behaviour and error [e.g. didLoadResponse: theResponse, didFailWithError: theError], so all situations will be covered.
I would reserve exception to situations like errors in writing to disk, or remote servers being down - actually situations that would break the application.
You would have a performance problem.If an exception is thrown, that's fine while you debug the program.But while the application is run by there you may not want that this happens.
My suggestion is to use exceptions only for debug, then you disable them for the release and you use more suitable apporaches like NSError.
Let's suppose that the user types a URL and this URL is invalid.You have to load a web page.During the debug you may just throw an exception, but when you have the release you could just ignore the wrong URL, and don't display the page, or run a NSAlertPanel to display the error.
Use tty/catch for exceptions only, not as a replacement for if/then.Overhead is very expensive.
I just did some testing on an iPad. It appears that a #try/#catch block introduces very little performance penalty unless an exception is actually thrown. But if an exception is thrown, the penalty is substantial. You don't say what environment you are using. So your milage may vary.
I'm new to Objective-C world. What I have noticed while studying some iOS/Mac apps is that try -catch is rarely used, if used at all.
For example in Java it is used almost all the time.
Why isn't it so common in Objective-C ?
Exceptions in Objective-C are generally to be used for truly exceptional circumstances and almost always programmer error. To convey a recoverable error use the NSError** pattern.
There are a lot of SDK methods that take an NSError** parameter and return BOOL. To indicate an error they return false and feed an error back through the error parameter to communicate info.
Exceptions are used, but generally for cases in which there is some failure at the runtime level - e.g. some object can't handle a selector. Although it may seem contrary to what I just wrote, exceptions tend to indicate an error in design rather than a runtime error.
The NSError** idiom is all you need for things such as failed URL connections, data conversions, etc, where an error condition exists but a program really shouldn't be killed outright.
Start reading: Error Handling Programming Guide
I have recently read Apple's sample code for MVCNetworking written by Apple's Developer Technical Support guru Quinn "The Eskimo!". The sample is really nice learning experience with what I guess are best development practices for iOS development.
What surprised me, coming from JVM languages, are extremely frequent assertions like this:
syncDate = [NSDate date];
assert(syncDate != nil);
and this:
photosToRemove = [NSMutableSet setWithArray:knownPhotos];
assert(photosToRemove != nil);
and this:
photoIDToKnownPhotos = [NSMutableDictionary dictionary];
assert(photoIDToKnownPhotos != nil);
Is that really necessary? Is that coding style worth emulating?
If you're used to Java, this may seem strange. You'd expect an object creation message to throw an exception when it fails, rather than return nil. However, while Objective-C on Mac OS X has support for exception handling; it's an optional feature that can be turned on/off with a compiler flag. The standard libraries are written so they can be used without exception handling turned on: hence messages often return nil to indicate errors, and sometimes require you to also pass a pointer to an NSError* variable. (This is for Mac development, I'm not sure whether you can even turn exception handling support on for iOS, considering you also can't turn on garbage collection for iOS.)
The section "Handling Initialization Failure" in the document "The Objective-C Programming Language" explains how Objective-C programmers are expected to deal with errors in object initialization/creation: that is, return nil.
Something like [NSData dataWithContentsOfFile: path] may definitely return nil: the documentation for the method explicitly says so. But I'm honestly not sure whether something like [NSMutableArray arrayWithCapacity: n] ever returns nil. The only situation I can think of when it might is when the application is out of memory. But in that case I'd expect the application to be aborted by the attempt to allocate more memory. I have not checked this though, and it may very well be that it returns nil in this case. While in Objective-C you can often safely send messages to nil, this could then still lead to undesirable results. For example, your application may try to make an NSMutableArray, get nil instead, and then happily continue sending addObject: to nil and write out an empty file to disk rather than one with elements of the array as intended. So in some cases it's better to check explicitly whether the result of a message was nil. Whether doing it at every object creation is necessary, like the programmer you're quoting is doing, I'm not sure. Better safe than sorry perhaps?
Edit: I'd like to add that while checking that object creation succeeded can sometimes be a good idea, asserting it may not be the best idea. You'd want this to be also checked in the release version of your application, not just in the debug version. Otherwise it kind of defeats the point of checking it, since you don't want the application end user to, for example, wind up with empty files because [NSMutableArray arrayWithCapacity: n] returned nil and the application continued sending messages to the nil return value. Assertions (with assert or NSAssert) can be removed from the release version with compiler flags; Xcode doesn't seem to include these flags by default in the "Release" configuration though. But if you'd want to use these flags to remove some other assertions, you'd also be removing all your "object creation succeeded" checks.
Edit: Upon further reflection, it seems more plausible than I first thought that [NSMutableArray arrayWithCapacity: n] would return nil rather than abort the application when not enough memory is available. Basic C malloc also doesn't abort but returns a NULL pointer when not enough memory is available. But I haven't yet found any clear mention of this in the Objective-C documentation on alloc and similar methods.
Edit: Above I said I wasn't sure checking for nil is necessary at every object creation. But it shouldn't be. This is exactly why Objective-C allows sending messages to nil, which then return nil (or 0 or something similar, depending on the message definition): this way, nil can propagate through your code somewhat similar to an exception so that you don't have to explicitly check for nil at every single message that might return it. But it's a good idea to check for it at points where you don't want it to propagate, like when writing files, interacting with the user and so on, or in cases where the result of sending a message to nil is undefined (as explained in the documentation on sending messages to nil). I'd be inclined to say this is like the "poor man's" version of exception propagation&handling, though not everyone may agree that the latter is better; but nil doesn't tell you anything about why an error occurred and you can easily forget to check for it where such checks are necessary.
Yup. I think it's a good idea.. It helps to filter out the edge cases (out of memory, input variables empty/nil) as soon as the variables are introduced. Although I am not sure the impact on speed because of the overhead!
I guess it's a matter of personal choice. Usually asserts are used for debugging purpose so that the app crashes at the assert points if the conditions are not met. You'd normally like to strip them out on your app releases though.
I personally am too lazy to place asserts around every block of code as you have shown. I think it's close to being a bit too paranoid. Asserts might be pretty handy in case of conditions where some uncertainity is involved.
I have also asked this on Apple DevForums. According to Quinn "The Eskimo!" (author of the MVCNetworking sample in question) it is a matter of coding style and his personal preference:
I use lots of asserts because I hate debugging. (...)
Keep in mind that I grew up with traditional Mac OS, where a single rogue pointer could bring down your entire machine (similarly to kernel programming on current systems). In that world it was important to find your bugs sooner rather than later. And lots of asserts help you do that.
Also, even today I spend much of my life dealing with network programs. Debugging network programs is hard because of the asynchrony involved. Asserts help to with this, because they are continually checking the state of your program as it runs.
However, I think you have a valid point with stuff like +[NSDate date]. The chances of that returning nil are low. The assert is there purely from habit. But I think the costs of this habit (some extra typing, learning to ignore the asserts) are small compared to the benefits.
From this I gather that asserting that every object creation succeeded is not strictly necessary.
Asserts can be valuable to document the pre-conditions in methods, during development, as design aid for other maintainers (including the future self). I personally prefer the alternative style - to separate the specification and implementation using TDD/BDD practices.
Asserts can be used to double-check runtime types of method arguments due to the dynamic nature of Objective C:
assert([response isKindOfClass:[NSHTTPURLResponse class]]);
I'm sure there are more good uses of assertions. All Things In Moderation...
What’s the rationale behind the Cocoa exception policy - or why use exceptions only for programmer errors?
I understand that exception used to be rather expensive so one would not want to overuse them. But that changed with the modern runtime and it’s zero-cost exceptions. I also understand that the use of exceptions to do general control flow is not a good idea because it could lead to code that is rather hard to understand.
But why should one use exceptions to signal programmer errors? For that case logging a message followed by abort() should be enough. Why should I write a #catch(...) block to handle a programmer error instead of fixing the actual mistake? I’ve been thinking about this a lot and I haven’t found any reasonable use of an exception for a programmer error.
(As a side note/question: I’ve written a recursive descent parser, and I’m planning on using exceptions in there for handling errors. Seems to be much more reasonable to me than adding an out parameter to every single function in there and manually check for an error everywhere. Of course I’ll catch any exceptions I throw in the top level methods that get called from the outside. Anyone think that’s a bad use for exceptions?)
Update: The real question
Thanks for all the answers so far. They all are true, but they don’t actually answer my question. So I guess I wasn’t really clear about it, sorry for that. So here’s the real question:
Why does Cocoa throw exceptions for programmer errors (or assertions) at all? One isn’t supposed to catch them, and actually writing code that handles a programmer error somewhere down the call stack is not a good idea anyways. Seems to me that exceptions there are a wasted effort. Simply logging the error and calling abort() (which exits the program) should be enough. So what’s the advantage there of actually having an exception thrown?
I understand why exceptions are not generally used and discouraged - most parts of Cocoa are just not exception safe. And that’s not the question here. I hope I made this clear now.
Why should I write a #catch(...) block to handle a programmer error instead of fixing the actual mistake?
In most cases, you wouldn't. In Objective-C, you generally don't handle exceptions. If an exception occurs, it causes a crash, and then you fix the bug -- hopefully you catch this during testing.
Of course, in some cases this doesn't work out. Maybe you do except an exception and you can workaround it, so you catch it. Or there's there rare API that'll throw exceptions instead of using error objects.
To be honest, I very, very rarely use try/catch in my Objective-C code.
As for the rationale, I think it's largely due to Objective-C's C heritage. Back in the early 80s when Objective-C was developed, exceptions were kind of "new" (i.e., not in many mainstream languages yet), and Objective-C catered more to the C tradition of using NULL or an out parameter to signal errors.
Your question explicitly assumes that "one isn’t supposed to catch them." This is incorrect. The programmer isn't expected to catch them under normal circumstances, but that isn't to say that they must never be caught for any purpose.
Example: I'm not sure if it does anymore since it's much less buggy these days, but I know it at least used to be the case that Xcode would catch exceptions and put up a dialog saying, "Such-and-such happened. It doesn't appear to be a critical problem, but you should probably save and restart the program to avoid any trouble in the future."
Why does Cocoa throw exceptions for
programmer errors (or assertions) at
all? One isn’t supposed to catch them,
and actually writing code that handles
a programmer error somewhere down the
call stack is not a good idea anyways
Ah!
Three reasons leap to mind.
One, if you catch an exception more or less at your main run loop you could autosave state to a temporary location, crash, and on restart have a "try to restore from just before the crash, warning: may cause another crash and you should check your data very carefully" dialog/sheet/thingie. Or even just catch the exception and tell the user to do a "Save As", quit and restart.
Two, things like the unit test framework make good use of exceptions to abort the current test (logging a failure), and continuing with the rest of the tests. This lets you see if a change you made has one regression (that happens to index a NSArray out of bounds), or if you have six regressions (one or more of which throw an exception).
Three, maybe when added to ObjC it was intended to handle many kinds of errors with exceptions, and after real world experience the useful scope was determined to be "nearly fatal errors only".
The main reason for avoiding throwing exceptions is that you may accidentally throw them through stack frames that are not exception aware. For instance, if a data source for a table view throws an exception, that is not caught and handled before the delegate method returns control to the table view, it might cause all sorts of trouble as it unwinds the table view's stack frames, side stepping various releases of temporary objects and other resources.
Having said that, I personally like exceptions and use them wherever I think they are the natural thing to do, but with the caveat of never allowing them to propagate to code that is not documented as exception aware.
There are likely a lot of reasons. The "historical reasons" others have covered is sufficient to explain the current state of affairs, but there are other possibilities.
Another possibility is Objective C is not typically a "Resource Acquisition Is Initialization" kind of language (yes this is more a library issue then a language issue, but it is real). So most Objective C code that has an error thrown through it will leave invalid program state (things still locked, over retained objects). All things you could deal with if you were thinking about it, and not all things RAII would magically fix (there is a lot of exception unsafe C++ code out there, and C++ is largely RAII).
As noted above stating that you do handle an exception is free(ish), but actually having one thrown is costly (maybe an order of magnitude or two more costly then an extra parameter and a conditional check). So if your parser (for example) uses them to signal errors in parsing, being given a document with a lot of errors can take a LOT longer to parse then if you had explicit checks for an error parameter.
Personally I like exceptions, and would prefer to throw exceptions from my libraries when things "go wrong", but that isn't the Cocoa way, so I use exceptions to handle programmer errors and an error indication and NSError** for other things. It isn't great, but it makes it so other people can use my libraries without having to learn a new way to write Objective C code.
The modern runtime does not give you zero-cost exceptions, it gives you exceptions that only incur their cost if an exception is thrown.