Hi Mom! (Photo credit: Huffington Post) |
This is when you have lots of places where your code prints out something - Hi Mom is fine, tho' you often want something more informative - but the key is it prints out on the console, and you can trace its execution by checking these points, and the data output at those times. It's the best debugging technique I know.
It's the traditional "printf" style of debugging as some call it. An elite coder friend who coined the term did it I think because "Hi Mom" is really quick and memorable - it highlights the fact that when you're doing this kind of debugging you want a quick edit-compile-run loop so lots of typing is a pain. And "Hi Mom" is short. It's just flagging that you reached that point.
It seems pretty obvious perhaps, but in these days of high-powered IDE's (like XCode) and symbolic debuggers that lead you by the nose through your code as it runs, it might seem that Hi Mom is a bit past it and long in the tooth. Far from the truth!
It might also seem like hard work - writing more code to debug the code I've already got? Wrong again!
Symbolic debuggers are a pain sometimes - they don't always work especially if your bug has messed up the stack. Getting a breakpoint just where and when you need it is not always straight forward. Getting information about the variables you want to see in the right format doesn't always come easy either. When code is multi-threaded or backgrounding, or you have to interact with the UI using the debugger is not always convenient.
So Hi Mom has some mileage here, even in these days of magic IDE's.
What about all that work typing tho' - especially when Objective-C does not give you a nice __FILE__ or __LINE__ macro to use like C++ does?
Here's a nice snippet I came up with that I'm using a lot - its a macro which uses a bit of token pasting:
#define MARK(object) NSLog(@"%@::%@ MARK - %s: %@", \ NSStringFromClass([self class]), \ NSStringFromSelector(_cmd), #object, object)
It gives me output that looks like this:
2013-04-26 22:21:31.994 Ethex2080[24072:c07]\ UIStateManager::graphSearchFromNode:toNode: MARK - nodeStart: Location #501
Breaking this down:
- The time stamp and binary name come from NSLog
- the class name and method name come from the two "NSStringFrom..." functions
- MARK (my version of "Hi Mom!") tells me its from a "MARK" macro call
- so I can see from the console what it is, if I have forgotten to remove one
- The string nodeStart: is the name of the variable
- (from a c-pre-processor token paste, the #object) and
- then the results of calling the -(NSString *)description function on that variable.
In fact I put it in my global project declarations file which is one of the headers which gets included in my precompiled header. That way its always available in any code I write in the project, without having to go hunting for the include or import:
//
// Prefix.pch #ifdef __OBJC__ #import <UIKit/UIKit.h> #import <Foundation/Foundation.h> #import "cocos2d.h" #import "Ethex2080Utils.h" #endifNow in my code that I'm debugging I can quickly drop in a statement like this:
- (void)doSomethingWeird:(NSArray *)someStuff { MARK(someStuff); // rest of stuff }
This gives me a nice debug line with
- the name of the class
- the name of the function that is running
- the name of a key variable I'm dumping
- the description (dump) of that variable
- ultra quick to type - no need to type the name of the variable even
- easy to find and remove before I do my git commit
- being a macro it can capture the name of the function (a debug function could not)
Feel free to use this if it helps (I hereby place this snippet in the public domain) and good luck as you "Hi Mom" your way to bug-free code!