38

I am using NSAssert() calls within an iPhone application and my understanding from the Apple docs is that assertions are not compiled into the code if NS_BLOCK_ASSERTIONS is defined.

To turn off assertions, in a header file I declare: #define NS_BLOCK_ASSERTIONS

However, the assert code still seems to run.

Is there something I am missing here?

Thanks

John

John Muchow
  • 4,798
  • 8
  • 40
  • 40

2 Answers2

63

If you created your Xcode project based on one of the standard templates, the Cocoa headers (including NSException.h which contains the NSAssert macros) will get preprocessed before any other files in the project. A #define NS_BLOCK_ASSERTIONS in any of the project's header or implementation files therefore has no effect on the NSAssert macros.

Try putting NS_BLOCK_ASSERTIONS into the preprocessor macros of your target or even project (for the release configuration only):

GCC_PREPROCESSOR_DEFINITIONS = NS_BLOCK_ASSERTIONS

Or put #define NS_BLOCK_ASSERTIONS into the prefix (.pch) header before the #import <Cocoa/Cocoa.h> or #import <Foundation/Foundation.h> lines.

puzzle
  • 6,071
  • 1
  • 25
  • 30
  • 14
    Note that in Xcode 4.2, the templates have this already set up for you: assertions are blocked in a Release build. – matt Nov 02 '11 at 15:45
  • 5
    I think it's been changed again. In Xcode 5.0, the processing area under build settings contains a section named "Enable Foundation Assertions", and the defaults there are to enable for all build configurations: AdHoc, Debug, and Release. – dwsolberg Oct 14 '13 at 21:55
  • In Xcode 5.0.2, assertions are disabled for Release builds by default. – Randall Dec 12 '13 at 11:41
  • however as pointed out here http://prod.lists.apple.com/archives/xcode-users/2013/Oct/msg00134.html despite the different flag in Xcode 5, NSException.h still uses NS_BLOCK_ASSERTIONS. See my question which I'm about to comment on http://stackoverflow.com/questions/20377845/xcode-5-equivalent-of-ns-block-assertions-in-build-settings – Max MacLeod Mar 27 '14 at 10:41
14

As @dwsolberg mentioned, Xcode has a new build setting called ENABLE_NS_ASSERTIONS. For new projects its value for the release configuration is set to NO and for all other configurations to YES. You can use this setting as well as the widely used NS_BLOCK_ASSERTIONS approach which is still valid in Xcode 6.

Preprocessor Macro Approach

Foundation Assertion Build Setting

Assertions are a tool to track down bugs during development time and should never fire in productive code! Also exceptions should be used only if it is absoloutely neccessary, i.e. if something went so damn wrong that the programm is not able to continue execution. The Cocoa way is to give critical methods a boolean return value and parametrize them with an error object that can be set inside the method and can be used outside if the return value is NO.

Hope that helps some folks ;-)

blackjacx
  • 9,011
  • 7
  • 45
  • 56
  • 1
    Why shouldn't assertions be used in production code? That's like allowing silent data corruption instead of crashing! If a developer misuses my library API it should crash so he can fix it - debug or release. What's so special about assertions that they should be disabled in production but other runtime exceptions are allowed? – Monstieur Mar 13 '15 at 13:33
  • An app should not crash it should handle errors gracefully, capture them, present an error and additionally inform your bug tracking system. For libraries it is the same. You can ship debug versions and release versions of your lib. NEVER LET YOUR APP CRASH – blackjacx Mar 14 '15 at 16:39
  • Non recoverable errors can't be presented since the application is in an undefined state. It's no longer possible to continue execution. – Monstieur Mar 14 '15 at 21:26
  • I never had such an error in 6 Years iOS development, which should not mean that there isn't the possibility that such a thing can occur. But in that case you should overthink your app design and present an error on a higher (or the highest) level in your view hierarchy. A crash is the worst what can happen to your app! Sorry thats simply wrong. – blackjacx Mar 15 '15 at 22:16
  • What happens if you miss a null pointer assert and you send messages to a nil object and you presume everything went fine? The result can be user data corruption. You don't seem to understand the concept of "undefined state". The app cannot recover, and no meaningful error can be presented. It's equivalent to a programming error. It's like trying to terminate a worker thread that's hung. Once you terminate the thread, the stack is undefined and the app has to crash regardless of whether the main thread is working fine. You cannot recover from it unless the background thread returns gracefully. – Monstieur Mar 16 '15 at 06:19
  • At best you can something like " has encountered an unexpected error and must close. Please contact the developer for assistance.". You may have noticed some apps do this. – Monstieur Mar 16 '15 at 06:26
  • Yeah I saw this and I still think it is bad app behaviour. When you can recover by crashing and restarting the app, why can't you recover by reinitializing the application hierarchy and the app state on such an error? I know crash/restart is convenient but resettung the app internally should also be possible. – blackjacx Mar 16 '15 at 14:09
  • Anyways, it is not without reason why Apple set NS_BLOCK_ASSERTIONS in release build settings as default ;-) – blackjacx Mar 16 '15 at 14:10
  • You cannot recover anything from something like a thread termination (stack becomes undefined). The OS has to destroy the entire process and its virtual address space. The " will close" error *is* the "recovery" instead of just freezing. – Monstieur Mar 16 '15 at 14:12