Debugger
Originally written for TagLib, the Debugger module provides debugging macros and functions useful to any project using the Obj-C runtime.
Wherever possible, arguments to macros are evaluated only once. If you find this is not the case, please file a ticket.
Installation
debugger.h
is written to be included in your project's precompiled header, or any other place it is wanted. If using in a precompiled header, it must be bracketed inside an #ifdef __OBJC__
conditional, like so:
#ifdef __OBJC__
// …
#include "debugger.h"
#endif
Unfortunately, the same #ifdef __OBJC__
macro already present in debugger.h
doesn't have the same effect in Xcode (tested in 4.5+) (why?).
debugger.c
will need to be built and linked as appropriate.
Usage
Debugger provides the following utilities:
AmIBeingDebugged
DebugBreak
Check
NotTested
Log
Assert
NotReached
BailUnless
BailWithBlockUnless
BailWithGotoUnless
Used by DebugBreak
to determine if it's safe to interrupt execution. If DEBUG
is not defined, this is never called internally, but is still available.
If there is no debugger attached, does nothing. If DEBUG
is not defined, does nothing.
If DEBUG
is not defined, does nothing.
If DEBUG
is not defined, does nothing.
Prepends the file path, line number, and current function to the format string. Parameters are passed directly to NSString +stringWithFormat:
. If DEBUG
is not defined, does nothing.
Log
can be overridden by defining it before including debugger.h
, for example if you wanted to add a component prefix to messages in a file:
#define Log(fmt, ...) NSLog(@"MyComponent: %@", [NSString stringWithFormat:(fmt), ##__VA_ARGS__])
Messages sent to user-defined Log
includes only a simple message, omitting any file, line, or method information that may be available.
Example
Log(@"View hierarchy: %@", [[UIWindow keyWindow] recursiveDescription]);
If DEBUG
is not defined, does nothing.
Example
Assert(NO); // ifdef DEBUG, kaboom.
If DEBUG
is not defined, does nothing.
If DEBUG
is not defined, this macro still bails, but does not break into the debugger or log any messages.
Example
- (NSArray *)foo {
BailUnless(NO, (NSArray *)nil);
NotReached();
}
When using BailUnless
with a function or method returning void
:
- (void)foo {
BailUnless(NO,);
NotReached();
}
If DEBUG
is not defined, this macro still bails, but does not break into the debugger or log any messages.
Example
- (NSArray *)foo {
BailWithBlockUnless(NO, ^{
// Clean up…
return (NSArray *)nil;
});
NotReached();
}
When using BailWithBlockUnless
with a function or method returning void
:
- (void)foo {
BailWithBlockUnless(NO, ^{
// Clean up…
});
NotReached();
}
If DEBUG
is not defined, this macro still bails, but does not break into the debugger or log any messages.
Example
- (NSArray *)foo {
BailWithGotoUnless(NO, error);
NotReached();
error:
// Clean up…
return nil;
}
License/Credits
The most interesting code in this project is not originally mine, but was assembled, tested, and in some cases rewritten by me from public sources (Stack Overflow, public documentation, freely released snippets). Thus all code in this project is released to the public domain. While more complete attribution is provided in the source, credit is especially due for:
bool AmIBeingDebugged()
provided by an Apple TechNote.DebugBreak()
for iOS code built with toolchains that do not support__builtin_debugtrap
provided by m20.nl (now defunct)DebugBreak()
for OS X code built with toolchains that do not support__builtin_debugtrap
provided by Matt Gallagher