Debugging with Three20
TTDebug.h
contains a set of useful debug tools, including priority-based logging and
debug-only assertions. These macros deprecate the original Three20 TTLOG
macros and Xcode NSLog methods that were difficult to disable (and tended to cause an
unending stream of log messages). The goal of the new logging framework is to make it easy
to see the logs you care about.
Table of Contents
What is logging?
Writing text to a console or file, at it's simplest. In Xcode, we use the NSLog
method to write to the Xcode log, visible when running an application with the
debugger attached.
Three20 adds an extra layer that makes it easier to disable logging when you ship your app, selectively show certain logging messages, or make assertions only in development builds of your app.
How to enable Three20 logging
Define a DEBUG preprocessor definition in the GCC_PREPROCESSOR_DEFINITIONS
option in your debug target settings. You shouldn't define this for your release
build.
If you define DEBUG in the build you submit to the App Store, your app will be
rejected.
![]()
How to write to the log
The logging system introduces a new set of priority-based macros.
TTDERROR(text, ...) // Priority level 1 TTDWARNING(text, ...) // Priority level 3 TTDINFO(text, ...) // Priority level 5 TTDPRINT(text, ...) // Always prints
What does priority mean?
The log message will only be written if the log's priority level is below
the TTMAXLOGLEVEL. So if the max log level is 3, then no logging
messages with a priority level higher than that will be displayed (i.e.
TTDINFO).
If you don't explicitly set TTMAXLOGLEVEL, the default is set to
TTLOGLEVEL_WARNING, meaning only warning and error logs will
be displayed.
The standard output of TTDPRINT looks something like this:
TTDPRINT(@"Is this thing on?"); 2009-11-20 13:46:49.613 AppName /path/to/file/Filename.m(86): Is this thing on?
Conditional Logging
Conditional logging allows you to produce output only when a certain condition is met. A quick example:
TTDCONDITIONLOG(TTDFLAG_URLREQUEST, @"Request parameters: %@", request.parameters)
This will only produce the log if the flag TTDFLAG_URLREQUEST is set to a non-zero value.
All the available conditional log flags are listed and defined in
TTDebugFlags.h.
To turn them on, edit their values in your local copy of this file.
Debug-only assertions
It can often be useful to validate the parameters passed into a method. The method may return preemptively if the parameters are invalid or missing. This is a way to fail somewhat gracefully. When you're actively developing code, however, it would be ideal if the method could shout out to you "hey, listen!", letting you know that the method is being abused.
This is where TTDASSERT comes in. It works like a regular
assertion - in that if you pass a zero-value to it, it lets you know - but it has the nice benefit
of not crashing your app. Instead, it jumps straight into the debugger at the line that caused the
issue. It's also gracefully compiled away in release builds, so your shipping product will
never know they existed.
Consider this example:
-(void)safeAddSubview:(UIView*)view {
TTDASSERT(nil != view);
if (nil == view) {
return;
}
[self addSubview:view];
}
Let's say we then call [myView safeAddSubview:nil]. In debug builds of the app, calling this
will now toss us into the debugger at the culprit line and output a quick log explaining the
problem.
2009-11-20 14:10:53.096 AppName... /path/to/file/Filename.m(86): TTDASSERT failed: nil != view
Some things to note about debug assertions.
Debug assertions will only fire in the simulator. On debug device builds the assertion will fail, output a log message, and then carry forward.
If you're in the simulator and debug assertions aren't starting up the debugger, it's likely because you're not starting the app with gdb attached. To ensure that you always attach gdb to the app when you start it, use the hot-key Cmd+Y instead of Cmd+Enter.
blog comments powered by Disqus