See also Apple’s technote at http://developer.apple.com/technotes/tn2004/tn2124.html, which contains a wealth of info about API-specific techniques and tools.
Code Flow Tracing
NSLog(@”%s”, PRETTY_FUNCTION, nil) will display the prototype for the currently executing function/method in the console log. It is useful for “tracer” style debugging.
A quick way to comment out NSLog statements (if your code becomes littered by them) is to get into the habbit of always having at least one tab in front of any NSLog statement. This allows you to find and replace “NSLog" with "//NSLog" (XCode's default setting is to replace tabs with four spaces). If you have an NSLog statement that is part of an if/else statememt then only use one space to separate the NSLog statement from any code in front of it (to avoid altering any logic).
-(void)someMethod {
NSLog(@"someMethod entered");
if(someCondition)NSLog(@"condition met");
elseNSLog(@"condition not met");
}
To make the NSLog statements active again you just have to find and replace "//NSLog" with "NSLog"
* **NOTE:** A better way to comment and uncomment NSLog or any other desired text is to use Project Builder's regular expression find. Be sure to limit the location of where to search for text to "this project, no frameworks". In the Find text field type **(NSLog([ \r\n\t\(]+))**, and in the Replace text field type **// \1**. To uncomment your NSLogs: in the Find text field type **// (NSLog([ \r\n\t\(]+))**, and in the Replace text field type **\1**. *
**Or, my favorite approach:**
Put the following in a header, e.g. DebugUtils.h:
#if MY_DEBUG_FLAG
#define DEBUG_OUTPUT( a ) NSLog( a )
#define DEBUG_OUTPUT1( a, b ) NSLog( a, b )
#else
#define DEBUG_OUTPUT( a ) // (a)
#define DEBUG_OUTPUT1( a, b ) // (a,b)
#endif
and then to add -DMY_DEBUG_FLAG=1 to the OTHER_CFLAGS of your "Debug" build style in ProjectBuilder (click the = to turn it into += so it doesn't overwrite any other flags). This will automatically define the debug flag and you'll get debugging output for debug builds while release builds ("deployment") will have the macro expand to no code at all. This requires a separate macro for each number of parameters, though, as the C Preprocessor doesn't support va_arg macros yet... (UliKusterer 2003-10-06)
With C99, you can make portable varargs macros:
#define DEBUG_OUTPUT(fmt, ...) NSLog(fmt, ## __VA_ARGS__)
That #define will work for any number of arguments to NSLog. (MikeAsh 2004-03-13)
Worth noting: The introduction to the example above said 'tabs', but the example itself used spaces. Tabs aren't spaces. The technique described will work either way; just use a tab instead of however-many spaces. And you should be indenting your code anyway. *--boredzo* (2004-09-20)
Also worth noting: Speaking of NSLog, check out this excellent article: "A Better NSLog" at http://www.borkware.com/rants/agentm/mlog
or its follow up at Hopeless Geek ( http://www.hopelessgeek.com/2005/11/18/better-logging ) Simple to implement and will provide file, function and line number of the log call.
----
**Backtrace All Threads**
"t a a bt" in gdb's console will get you a backtrace of all threads, not just the current one. (The full command is "thread apply all backtrace", but gdb will accept abbreviations.)
----
**Environment Variables That Affect Your App**
Read /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSDebug.h for interesting environment variables you can set to get extra debugging information. NSZombieEnabled, for example, will tell you if you are sending messages to objects you have released. On 10.4 and below, an important exception is that NSZombie does **not** work with any 'toll free bridged' class. So NSZombie won't help you with catching over releases of NSStrings, etc. CFZombieLevel however will help in those cases. On 10.5, NSZombie works with all classes, so CFZombieLevel is not needed.
One way to set this variable is to select "Edit Active Target" from the Project menu, choose the "Executables" tab, then the "Env Vars" tab. Add a variable called NSZombieEnabled, with value YES.
----
**Breaking on Exceptions**
*Note: "Double-Click for Symbol" no longer exists in XCode 4*
You can break into the debugger whenever an exception is raised. Go to the Breakpoints window in Xcode, and double click "Double-Click for Symbol". Add a breakpoint for "-[NSException raise]" and for "objc_exception_throw" to the breakpoints list.
You can also accomplish this from the gdb console by entering "b -[NSException raise]" or "fb -[NSException raise]", and then the same command for objc_exception_throw. The latter is not frequently encountered in Tiger but is essential in Leopard, as much of the internal Cocoa code has moved to @throw which bypasses -[NSException raise] and will not trigger a breakpoint set there. You might want to add these to your ~/.gdbinit file.
When stopping at objc_exception_throw the exception object is stored in $edx ($rax on x86_64), you can print information about the exception in the gdb console like so:
(gdb) po [$eax className]
NSException
(gdb) po [$eax name]
NSAccessibilityException
(gdb) po [$eax reason]