Software Development

Run simple diagnostics on your iOS apps: Part 2

Refine basic diagnostic techniques that are extremely simple to set up and use, but not always obvious to the new iOS developer.

1_skantner_computer_diagnostics.jpg
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

a_skantner_simple_diag_2.png

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

b_skantner_simple_diag_2.png

Figure C

c_skantner_simple_diag_2.png

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

d_skantner_simple_diag_2.png

  • 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

e_skantner_simple_diag_2.png

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.

About

Scott Kantner started his IT career on a Radio Shack TRS-80 model I back in 1978. He is CTO of a hosting/colocation firm, a tech writer, and an avid iOS app developer. He has several music-related apps in the App Store that you can learn about at OnS...

0 comments