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
permanent link
· Topic/Cocoa
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.