Dan Wood: The Eponymous Weblog (Archives)

Dan Wood Dan Wood is co-owner of Karelia Software, creating programs for the Macintosh computer. He is the father of two kids, lives in the Bay Area of California USA, and prefers bicycles to cars. This site is his older weblog, which mostly covers geeky topics like Macs and Mac Programming. Go visit the current blog here.

Useful Tidbits and Egotistical Musings from Dan Wood

Categories: Business · Mac OS X · Cocoa Programming · General · All Categories

Fri, 22 Dec 2006

Class Posing as a useful Debugging Technique

Third past today! Since I just posted a "gripe" entry, I thought I would also post something constructive. I wanted to talk about how cool class posing is for debugging.

We have used class posing quite a few times just to insert some extra warnings for our debug builds. A lot of times, you can catch a nasty condition before it happens and provide some information about what's happening. For instance, if you are only supposed to call a particular method from the main thread, a posed subclass could define your entry points to log an error message if it's being called from a background thread.

For example, I wanted to log some information whenever an NSThread got detached, so I could see where all my application's threads were coming from. So I created a subclass of NSThread called, unimaginatively, MyThread:

@interface MyThread : NSThread
@end

This class has two methods (in an @implementation block, of course). The first is used to force the subclass to be used in place of its parent class:

+ (void) load
{
    [self poseAsClass:[NSThread class]];
}

The second is a redefinition of +[NSThread detachNewThreadSelector: toTarget: withObject:]. It logs some useful information and then calls the "super" implementation to actually do the work. I've simplified my code a bit here but you should get the idea:

+ (void)detachNewThreadSelector:(SEL)selector
                       toTarget:(id)target
                     withObject:(id)argument;
{
    LOG((@"Detach -[%@ %@%@]", target, NSStringFromSelector(selector),
        argument));
    [super detachNewThreadSelector:selector
                          toTarget:target
                        withObject:argument];
}

Generally I don't need this logging to happen, so the code is normally commented out with #ifdef 0. But when I need to know what's going on with threads, this is very helpful.

I've also use this technique to debug my bindings and log each instance of -[NSObject bind:toObject: withKeyPath: options:] and -[NSObject unbind:], all the initialization methods on QTMovie to make sure that the movies are created on the main thread, and so forth.