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

Better description of data

One thing that drives me crazy about debugging in XCode is how the default print-object command invokes debugDescription on an object. Normally this is the same as description, but for certain data objects, it's much less readable than plain old description. OK, it has a bit more information, but it's generally not what I'm looking for and it's formatted so poorly.

What I do in our application is to redefine debugDescription in terms of description for debug builds. (I bracket this code within and #ifdef so it's not built for the release version.) Here's NSDictionary:

@implementation NSDictionary ( OverrideDebug )

- (NSString *)debugDescription
{
    return [self description];
}

@end

I do something similar for NSSet.

Easy enough, right? For NSArray, I've gone a step further by only printing the first 20 or so items in the array. That way an array with thousands of items won't fill up my terminal!

@implementation NSArray ( OverrideDebug )

- (NSString *)debugDescription
{
    #define MAXARRAYSHOW 20
    if ([self count] > MAXARRAYSHOW)
    {
        NSArray *subArray = [self subarrayWithRange:
            NSMakeRange(0,MAXARRAYSHOW)];
        return [NSString stringWithFormat:@"%@ [... %d items]",
                    [subArray description], [self count]];
    }
    else
    {
        return [self description];
    }
}
@end

For NSDictionary, I've gone all out and made a much more useable description. This implementation shows the data in a nicely formatted Hex/ASCII dump that's much more scannable. I also cut it off at 1024 bytes since I don't really want to see much more than this, and I hate to have to wait for a megabyte-long chunk of data to finish displaying.

Note that I've also gone ahead and re-implemented description, not debugDescription, so I always get this new style of display.

@implementation NSData ( description )

- (NSString *)description
{
#define MAXDATABYTES 1024
    unsigned char *bytes = (unsigned char *)[self bytes];
    unsigned length = [self length];
    NSMutableString *buf = [NSMutableString stringWithFormat:
        @"NSData %d bytes:\n", length];
    int i, j;

    for ( i = 0 ; i < length ; i += 16 )
    {
        if (i > MAXDATABYTES)       // don't print too much!
        {
            [buf appendString:@"\n...\n"];
            break;
        }
        for ( j = 0 ; j < 16 ; j++ )    // Show the row in Hex
        {
            int offset = i+j;
            if (offset < length)
            {
                [buf appendFormat:@"%02X ",bytes[offset]];
            }
            else
            {
                [buf appendFormat:@"   "];
            }
        }
        [buf appendString:@"| "];   // now show in ASCII
        for ( j = 0 ; j < 16 ; j++ )
        {
            int offset = i+j;
            if (offset < length)
            {
                unsigned char theChar = bytes[offset];
                if (theChar < 32 || theChar > 127)
                {
                    theChar ='.';
                }
                [buf appendFormat:@"%c", theChar];
            }
        }
        [buf appendString:@"\n"];
    }
    [buf deleteCharactersInRange:NSMakeRange([buf length]-1, 1)];
    return buf;
}
@end

Can anybody think of more improvements to the standard ways out describing objects?