What's the Point of Nsassert, Actually

What's the point of NSAssert, actually?

Assert is to make sure a value is what its supposed to be. If an assertion fails that means something went wrong and so the app quits. One reason to use assert would be if you have some function that will not behave or will create very bad side effects if one of the parameters passed to it is not exactly some value (or a range of values) you can put an assert to make sure that value is what you expect it to be, and if it's not then something is really wrong, and so the app quits. Assert can be very useful for debugging/unit testing, and also when you provide frameworks to stop the users from doing "evil" things.

NSAssert vs. assert: Which do you use, and when?

To answer your two questions:

  1. There should be very little performance hit for leaving in an assertion, unless the actual action in the assertion is time consuming (e.g. assert([obj calculateMeaningOfLife] == 42)). An assertion should be no different than an extra if statement, performance-wise. The reason for stripping out assertions in release builds is that they are essentially a debugging tool--they catch inconsistent internal program state at runtime. From a developer perspective, it's much better for an app to crash as soon as something goes wrong, but from a user perspective it's arguably less annoying if the app doesn't crash (unless letting the app run with abnormal state causes something horrible to happen), and exposing development details in error messages can be off-putting. There are good arguments on both sides--if I remember correctly, Code Complete recommends stripping them out but The Pragmatic Programmer recommends leaving them in. In any case, assertions are not a substitute for proper error handling and should only be used for programming errors.

  2. The basic difference between an NSAssert and a regular assert is that an NSAssert raises an exception when it fails while an assert just crashes the app. NSAssert also lets you supply fancier error messages and logs them. Practically, I really don't think there's much difference between the two--I can't think of a reason to handle an exception thrown by an assertion. (To split hairs, I think NSAssert usually involves less typing because you don't have to include assert.h, but that's neither here nor there.)

What are assertions or NSAssert good for in practice?

Broad use of NSAssert() will not turn ObjC into Eiffel, but it's still a fairly good practice as long as you keep in mind how it's actually implemented and what it's doing. Things to keep in mind about NSAssert():

Xcode does not turn off NSAssert() in Release mode by default. You have to remember to add NS_BLOCK_ASSERTIONS to GCC_PREPROCESSOR_DEFINITIONS in you xcconfig. (You are using xcconfigs, right?) A common issue is to assert non-nil in cases where nil will quietly work; this can mean field crashes for things that could have gracefully recovered. This is unrelated to the NDEBUG macro used by assert(), and you have to remember to define both if your code includes both types of assertions.

If you compile out NSAssert() in Release mode, then you get no indication where a problem happened when customers send you their logs. I personally wrap NSAssert() in my own macros that always log, even in Release mode.

NSAssert() often forces duplicated logic. Consider the case of testing a C++ pointer for NULL. You use NSAssert(), but you still need to use a simple if() test as well to avoid crashing in the field. This kind of duplicated code can become the source of bugs, and I have seen code that fails due to assertions that are no longer valid. (Luckily this is generally in Debug mode!) I have debated a lot how to create a macro that would combine the assertion and if(), but it's hard to do without being fragile or making the code hard to understand.

Because of the last issue, I typically put "NSAssert(NO, ...)" in an else{} clause rather than performing assertion at the top of the method. This is not ideal because it moves the contract away from the method signature (thus reducing its documentary benefit), but it is the most effective approach I've found in practice.

What is the main use of NSAssert Vs. NSException

Assertions are generally used during development only and are compiled-out of the app when in release mode (this is controlled by NS_BLOCK_ASSERTIONS). Exceptions, on the other hand, can be used at all times.

When an exception is thrown, it travels back up the call chain, until it is either caught (and reported, ignored, or another exception is thrown) or it reaches the top, in which case it will cause the app to crash. It can be considered part of the contract of a class method and needs to be documented so the caller can handle this correctly.

Assertions are really a runtime developer check that ensure that something (generally a instance variable) is in a certain state and if it's not then abort() in order to bring the issue to the developers attention. It's a developer sanity check to check that something is in the state the developer expects it to be.

Will NSAssert takes any memory on the device in iOS?

Maybe this will answer your question

It's important to note that as of Xcode 4.2, assertions are turned off
by default for release builds, which is accomplished by defining the
NS_BLOCK_ASSERTIONS macro. That is to say, when compiled for release,
any calls to NSAssert & co. are effectively removed.

Source: http://nshipster.com/nsassertionhandler/

If you leave them enabled, then yes they come at a cost (obviously they need to be evaluated) and depending on what code you have them execute it differs. For simple nil comparisons it is negligible.

For further reference see: http://www.mikeash.com/pyblog/friday-qa-2013-05-03-proper-use-of-asserts.html

Specifically this passage

The runtime cost should be negligible, and if it's not, then you should redo your asserts to fix that.

Why NSAssert1, etc instead of NSAssert?

Current versions of NSAssert() use preprocessor variadic macros, i.e., __VA_ARGS__. Since variadic macros are a C99 feature, my guess is that older versions of the SDK didn’t allow variable arguments in NSAssert(), hence the need for NSAssert1(), NSAssert2(), etc.

If you try to compile

NSAssert(0, @"%@%@", @"foo", @"bar");

using -std=c89 or -ansi (ISO C90, an older version of C that doesn’t support variadic macros), you get a compiler error:

error: too many arguments provided to function-like macro invocation
NSAssert(0, @"%@%@", @"foo", @"bar");

For that code to compile with -std=c89 or -ansi, you need to use NSAssert2():

NSAssert2(0, @"%@%@", @"foo", @"bar");

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.

Should the way NSAssert are handle be raised as a bug

Personally, I prefer the AssertMacros, which guarantee that the code will be executed, but don't use assertions.

http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/EXTERNAL_HEADERS/AssertMacros.h

Does the NS_BLOCK_ASSERTIONS disable both NSAssert and assert() calls?

No, assert() is controlled with the NDEBUG symbol:

#ifdef NDEBUG
#define assert(e) ((void)0)
#else
...

(see /usr/include/assert.h if you have the Xcode Command Line Tools installed, or elsewhere in the Xcode.app bundle, if not).



Related Topics



Leave a reply



Submit