I tend to use NSLog a lot as I'm developing. I add log statements all over the place as I'm developing, to check that my methods are getting called when I think they should be, to trace down memory problems, to display values as I debug my code, etc, etc.
(If you don't know about NSLog, you should. It's a simple function that takes a format string and a variable number of parameters, and writes the result to the debug console. It's really, really useful in figuring out what's going on with your code as you're developing.)
The problem is, I wind up with a ton of log statements in my code. They start to make the log get clogged with stuff I probably don't care about any more.
So, I try to comment out log statements once I'm finished debugging a bit of logic. However, that's kind of unwieldy. I might have 8 or 10 log statements scattered through several classes that I added to follow a feature I was adding. Commenting them out is a pain. Worse, If I go back later and enhance that feature, I may need to turn the log statements back on.
Also, some log statements slow down a running program so much that it becomes hard to use. If you log the users's touch/mouse movements (for iOS or Mac OS, since some of us develop for both) as they drag, for example, you can generate thousands of log entries, and the code can get quite slow because generating all that text takes a while.
Wouldn't it be nice if you could control NSLog statements in logical blocks of your choosing, and switch those blocks on or off in a running program, either in the debugger or by making a single code change?
Well, I decided to do something about it. I created a new function, dlog(), which is short for debug_log.
It is exactly like NSLog, except that it takes a new integer parameter at the beginning which is a combination of flags for what that debug statement does.
If you create a new view controller, for example, you might create a debug flag for dealing with that view controller.
If you're trying to track down an issue with auto-rotation, you might create a flag for auto-rotation debug statements.
If you're hunting down an over-release problem, you might add overridden versions of retain, release, autorelease, and dealloc.
As an example:
Say you have a view controller FooViewController, and you created a dlog flag K_FOO_VIEWCONTROLLER_MESSAGES for debug statements in that view controller.
And, if you're tracking down auto-rotation issues with that view controller, you might add another flag K_AUTOROTATION_MESSAGES.
When you add log statements to your FooViewController for rotation issues, they would look like this:
Code:
dlog(K_FOO_VIEWCONTROLLER_MESSAGES | K_AUTOROTATION_MESSAGES,
@"After rotation, view_xyz.frame = %@",
NSStringFromCGRect(view_xyz.frame) );
That tells the dlog function that the log statement relates to the FooViewController AND relates to auto-rotation methods.
The dlog.h file defines a number of globals that let you control which log statements are ignored, and which ones are actually sent to the console.
To excerpt from the code header:
The globals below control the behavior of the dlog() function. Calls to dlog() indicate what kind
of log statement they represent.
Code:
//dlog globals
extern uint32 log_if_any;
extern uint32 log_if_all;
extern BOOL disable_logs;
extern BOOL log_everything;
If disable_logs is true, all logs are disabled.
else if log_everything is true, all dlog messages generate log entries.
else if any of the flags passed in the dlog statment are set in log_if_any, the call generates a log entry
If
ALL of the flags passed in the dlog statment are set in log_if_all, the call generates a log statement
So, in our example of debugging auto-rotation issues with my foo view controller, I want to turn on log messages if they relate to both. So, I would do this assignment anywhere in my code
Code:
log_if_all = K_FOO_VIEWCONTROLLER_MESSAGES |
K_AUTOROTATION_MESSAGES;
That tells the dlog function that we want to send log messages to the console when both the K_FOO_VIEWCONTROLLER_MESSAGES and the K_AUTOROTATION_MESSAGES flags are set.
It might seem a little counter-intuitive to use bitwise OR to designate that we want to check one flag AND another flag, but the bitwise or operator ("|") is how you combine multiple bit flags into a single value.
Once you're done debugging the auto-rotation problem with the Foo view controller, you just comment out the code that sets the log_if_all global, and the log statements are turned off.
Later, if you need to debug auto-rotation problems in a BarViewController, you'd add a line like this to your app delegate's init routine:
Code:
log_if_all = K_BAR_VIEWCONTROLLER_MESSAGES |
K_AUTOROTATION_MESSAGES;
Now, the only log statements that get written to the console are log messages that relate to auto-rotation in the
Bar view controller.
Anyway, I've written and tested the dlog function, and it works great.
I had to do a little hocus-pocus to be able to redirect the variable list of parameters from the dlog() function call to the NSLog() call for messages that get logged, but you don't need to understand that part in order to use the function. Just import the dlog.h and dlog.m files into your project, and #import dlog.h in every file in your project (or more simply into a header file that is, in turn, imported into every file in your project. I've seen people use a file "includes.h" for a list of headers that are included in every file.)
You can download that dlog.h and dlog.m files by clicking the foliowing link:
dlog function archive