Objective-C: Assertion vs. Exception vs. Error
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 NSError
s 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 NSInternalInconsistencyException
s (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.