In Run
simple diagnostics on your iOS apps – Part 1
we saw how to use NSLog to gather diagnostic
information to easily debug problems with our code. However, we up ended with
the following rather complicated call to NSLog:

NSInteger count = 10;

NSLog(@"%s:%d: %@", __PRETTY_FUNCTION__, __LINE__,[NSString stringWithFormat:@"The value of counter is %d",counter]);

Which, when run inside a method named someMethod:,
produced the following output in the debug console. (Figure A)

Figure A

By using these statements throughout our source code, we can
find out not only the value of variables and properties at any point in the
execution path, but we can also quickly find the exact location in our source
code, right down to the method name and line number.

Nice as it is, there are two downsides to using these NSLog
statements as-is:

  • It is quite simply too
    much to type.
  • They aren’t needed when
    our app ships, and will simply slow down execution.

Using Xcode’s Instruments tool, I have observed NSLog
statements running for 30ms or more. Inside a loop of any length, this could
easily impact the responsiveness of your app.

So here in part II, we’ll tackle both problems.

Creating a compiler macro

To minimize the amount of typing we have to do, we’ll create
a compiler macro that is much shorter
in length than our NSLog statement. Whenever the compiler encounters the macro,
it will expand it into the full NSLog statement automatically.

When you open a new project in Xcode, a file called the prefix header file is created. Its default name is the name of the project
with the extension .pch and is automatically included in
every source file at compilation time. Figures B and C shown the default prefix
header file created by Xcode in our project from Part I.

Figure B

Figure C

Let’s add the following code to the bottom of
Diags-Prefix.pch:

#ifdef DEBUG

#define DLog(…) NSLog(@"%s:%d %@", __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:__VA_ARGS__])

#else

#define DLog(…) do { } while (0)

#endif

We are telling the compiler it should define a macro named DLog in one of two different ways
depending on whether the DEBUG variable is defined (which we will do next). If
DEBUG is defined, the compiler will replace any DLog
macros it finds with our fancy NSLog
statement and do any variable substitution necessary. Otherwise, the compiler
will create a DLog macro that
effectively does nothing.

Now instead of typing out the NSLog statement, we can simply
do the following:

DLog(@"The value of counter is %d",counter);

And the output will be exactly the same as in Figure A. With
that, we have taken care of our first problem. Now, we will tackle the second
problem.

Defining a compiler variable

Ideally, we want an automatic way to remove all of the DLog statements from our code when
we’re ready to ship to the App Store. We designed our macro such that it will
become the full-blown NSLog
statement only if a compiler variable named DEBUG is defined. We now need to set
that up in the build settings for the target of our project. To do so, follow
the steps below, which are keyed to Figure D.

Figure D

  • Click on the project in
    Files & Groups pane.
  • Click on the target.
  • Enter “flags” in
    the search box to quickly locate the “Other C Flags” section of
    the build settings.
  • Click on the “+”
    for the “Debug” build configuration.
  • Enter “-DDEBUG”
    as shown in Figure E.

Figure E

With this is place, we’re set to go. When we build our app
during normal development, Xcode uses the “Debug” build settings, so
any DLog statements will be
replaced with our special NSLog
statement. When shipping the app, we will build using the “Release”
build settings and Xcode will automatically generate DLog statements that essentially do nothing.

You might want to make it a habit to include the DLog macro in
the prefix header file at the start of every new project, or perhaps even come
up with a few variations of your own. It can save you a lot of work and
headaches during development and also help you diagnose support issues from your
customers much more quickly.