Smart usage of the DEBUG preprocessor macro in Obj-C

XCode automatically generates a preprocessor macro for debug mode, for you, i.e:

DEBUG = 1

So, if you want a piece of code to only be compiled into the app when debugging, you would wrap it in a #ifdef block:.

#ifdef DEBUG
//<your code here>
#endif

And inversely, if you only wanted to compile in a piece of code for release mode, you would wrap it in a #ifndef block:

#ifndef DEBUG
//<your code here>
#endif

You could also include the #else if you wanted to switch between certain pieces of code for debug and release respectively:

#ifdef DEBUG
//<your code here>
#else
//<your code here>
#endif

Thus whatever block you have running now in debug mode, will only be compiled in debug mode and the other part of the block will only be compiled in release mode.

What you were doing here is looking to see if a preprocessor macro has been defined or not defined, and compiling in pieces of code based on that. However, if you noticed at the top, XCode generates this macro with a value as well. So instead of looking to see if a macro was defined, you can instead look at the value:

#if DEBUG == 1
//<your code here>
#else
//<your code here>
#endif

This allows you to now switch between the code blocks by checking for a 1 or 0 for example, while still in debug mode. Effectively the same as switching between #ifdef and #ifndef. Based on this, one could make the assumption that XCode is being smart here, and regardless of the value being 1 or 0, the #else part would always be compiled for release mode, seeing as the macro isn't defined at all for debug mode then.

This is incorrect.

Switching to release mode would build the code as if the macro is defined as DEBUG = 0. Thus, you haven't gained anything by using this over #ifdef.

And this is where the smart usage comes in. By checking if the macro is defined as well as checking for the value of it, you are able to switch between the parts of the block, while in debug mode, also while making sure, that the #else part will always be compiled for the release build:

#if (defined DEBUG && DEBUG == 1)
//<your code here>
#else
//<your code here>
#endif

Giving you the certainty, that no matter how you had the settings while developing, the right piece of code will always be going into your release build.

Comments