New Toronto Group
 - New Toronto Group

Objective-C Debugging Overview

| Posted on November 18th, 2011 by Default Admin User


By Brandon Slack - Consultant

This is a simple guide that goes over some of the basics one should know when debugging Objective-C. Over the six years that I have spent working with Objective-C I have noticed some patterns and learned some tricks that have helped me to debug some really hard issues. I will be publishing various entries going forward on debugging tips and tricks. Starting first with the basics (console output) and moving onto more advanced techniques both in objective-c (posing, zombies, etc.) to gdb (how to use it, how to move your instruction pointer etc.) to using instruments. So check back often for further updates. Without further ado, I introduce Part I.


Part I: Console Output (The Basics)

This section walks you through the basics of using console output to debug. It starts off with a review of standard out and standard error, and explains the difference between buffered and unbuffered output, in particular, how that could effect your debugging output. It ends with a description of how to customize the logging output of an objective-c method through the overriding of the 'description' method.

Simplicity is usually the answer when it comes to debugging. Sometimes the quickest and easiest approach to debugging a problem is log statements. Whether you use a logger, or printf, or NSLog, getting output on what is happening is one of the most simple and powerful tools that can be used to solve problems.

For creating console output you would typically use one of the following functions:
void NSLog(NSString *format, ½);
int printf(const char * __restrict, ½);
int fprintf(FILE * __restrict, const char * __restrict, ...);

There are of course many other functions that would allow you to output to console, but those are the three big ones I often use. If you are working on a bigger project, you might even have developed your own that will output to both console and a log file, and perhaps even format the output for you.

Typically you would output to a file or console or to some other stream. There are two very common streams that are predefined in stdio for you.

stdout (Standard Out) -- This stream usually outputs all text to the console or terminal that you are working in. One thing to keep in mind with this stream is that it is typically a buffered stream, sometimes line buffered, sometimes buffered by size. The point is that you might write to stdout and not see anything appear on the console. You may write several lines to stdout and only see the first three or four. This is an important thing to understand that this stream will not output until its buffer is full or has reached a threshold. You can however force output of this stream prematurely by using the 'fflush' function which is also defined in 'stdio.h'. Calling this will immediately force everything in the buffer to be outputted. You should try to avoid calling this function when possible however as it does involve a small amount of overhead and could therefore be a small point of performance loss. When debugging an application that uses output to stdout, I typically have a fflush(stdout) command at the end of my run-loop.

stderr (Standard Error) -- This is the other pre-defined stream. It also typically outputs to console and is typically used to output diagnostics or error reporting information. A big difference between stdout and stderr is that stderr is unbuffered unlike stdout. This is again platform specific, and you should always double check, but scenario is that stdout is buffered and stderr is not. This means that anything you output to stderr should appear right away at the output terminal. This can cause some confusion for some people. As you could have a scenario like the following:
"Hello World" --> stdout
"Error Message" --> stderr
"Hello Again" --> stdout

Typically, at the output terminal, you would expect to see:
Hello World
Error Message
Hello Again

But what they might actually end up seeing is:
Error Message
Hello World
Hello Again

It also goes back to the fact that stdout might be buffered, and therefore will not be outputted right away, where as stderr is typically unbuffered and therefore outputted immediately. This is something important to keep in mind when debugging and outputting data.

One other important aspect to stdout and stderr is that there output locations can be redirected. Typically, they both go to terminal or console. However a user has the ability to pipe their contents to a file. Further, a user could pipe stdout to one file and all the stderr statements to another file if they so desire.

Output

The printf, and fprintf functions are both defined in stdio.h and is therefore part of the C standard library. The printf function will output to console on stdout all the time, where as fprintf, allows you to specify the file that you wish to output to. So typically you might find:
1) printf("Hello World\n");
2) fprintf(stdout, "Hello World\n");
3) fprintf(stderr, "Hello World\n");

Lines 1 and 2 are equivalent. Both go to standard out, where as line 3 is directed to standard error instead (and as previously explained might be unbuffered). Another important thing to note is that we have a '\n' at the end. This '\n' indicates that we want to start a 'newline'. The printf family of outputting does not automatically output to a new line each time you use it. You need to tell it when you want to start a new line.

The printf family of functions also allows you to output other information such as numbers, strings etc. You can output a number by doing:
printf("My number is %d\n", 14);

This will output
"My Number is 14"

The '%d' is a format specifier that dictates where the number should be positioned. A string would have a different format specifier as would characters and pointers etc. If you need a refresher on this, you should probably take a read of this:

http://www.cplusplus.com/reference/clibrary/cstdio/printf/

The same format specifiers will work in fprintf that work in printf.

NSLog Output
NSLog is an output function provided by the foundation framework which is typically included when you are building most Objective-C projects. It is very similar to the printf family of functions and can use the same format specifiers to output information from variables. There are however four differences:

1) NSLog is set to output to stderr (in contrast to printf).
2) NSLog always appends a '\n' (newline) to the end of your log statement for you. Therefore you no longer need to use '\n' at the end of your log statements to drop down to a new line. This is done automatically for you. Therefore, if you do add a '\n' at the end of your log statement you will drop down two lines instead of one.
3) NSLog accepts NSString objects as the format string as opposed to CStrings. E.g.
printf("Hello World\n");
NSLog(@"Hello World");

Notice the '@' symbol in objective-c means that we want this to be a NSString object. Also notice that no '\n' is needed.

4) A format specifier has been added, the '%@' format specifier. The '%@' format specifier is the specifier that you use to output Objective-C objects that inherit from NSObject (typically most objects). There are ways to output objects that do not inherit from NSObject, but thats beyond the scope of this introduction.

EDIT: The NSLog format specifiers can be found here:
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html

The most interesting part is the new format specifier '%@'. This allows us to print an object out to console. Say we have the following:
@interface Foo : NSObject {
int x;
}
@end

@implementation Foo

- init {
if((self = [super init])) {
½
}
return self;
}

- (void)dealloc {
½
[super dealloc];
}
@end

A typical object, and then we have:
Foo *f = [[Foo alloc] init];
NSLog(@"Output: %@", f);

What we would typically see go to the console is this:
Output: 

That is the name of the object, plus is memory address. This is a nice way of uniquely identifying a reference to an object, but nothing more, and it could be hard to follow. What you can do is add more information by overriding the NSOjbect's 'description' method. The description method accepts no parameters and always returns a NSString. Here is an improved version of Foo that will give us more output:
@interface Foo : NSObject {
int x;
}
@end

@implementation Foo
- init {
if((self = [super init])) {
½
}
return self;
}

- (void)dealloc {
½
[super dealloc];
}

- (NSString*)description {
return [NSString stringWithFormat:@"%@ - X: %d", [super description], x];
}
@end

Now when we do the following:
Foo *f = [[Foo alloc] init];
NSLog(@"Output: %@", f);

What we will see in the console is something like this:

Output: - X: 0

Notice how we now have information on the 'x' variable and its value. You will notice if you look at my override that I call 'super description' as well and put that at the begging of the string. This is not strictly required, but I have found when making subclasses, it is always nice to output the super classes description. You never know what it might have and what information it might add.

There is another 'special' method you can override that is often overlooked. It is called 'debugDescription'. This will get called, before 'description' when the print-object function is called. It can be useful when debugging, especially in the debugger where you might print out more detailed information then you might log. This will be discussed more in a future update.

Posted in C  | Comments (2)

Comments (2)

  1. Kelvin:
    Nov 21, 2011 at 01:50 PM

    Articles like make things really easy and simple to understand! This is a very good refresher on buffered outputs and why print statements are sometimes displayed out of order.

    I look forward to more Objective-C overviews.

  2. Mark:
    Nov 21, 2011 at 02:22 PM

    Nice overview and great point about the use of description. I've saved a lot of time debugging by adding descriptions for my classes.


Add a Comment





To use reCAPTCHA you must get an API key from http://recaptcha.net/api/getkey

Allowed tags: <b><i><br>Add a new comment: