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.
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.
Debugger provides the following utilities:
AmIBeingDebuggedDebugBreakCheckNotTestedLogAssertNotReachedBailUnlessBailWithBlockUnlessBailWithGotoUnless
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.
Log(@"View hierarchy: %@", [[UIWindow keyWindow] recursiveDescription]);
If DEBUG is not defined, does nothing.
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.
- (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.
- (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.
- (NSArray *)foo {
BailWithGotoUnless(NO, error);
NotReached();
error:
// Clean up…
return nil;
}
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_debugtrapprovided by m20.nl (now defunct)DebugBreak()for OS X code built with toolchains that do not support__builtin_debugtrapprovided by Matt Gallagher