I’m working on a project that makes extensive use of NSDictionaries. Buried deep in the model layer, there are dozens of calls to stringWithFormat: used to create dictionary keys. Here’s a quick example:

1
2
3
4
5
6
7
8
- (CGRect)rect:(NSString*)name inDict:(NSDictionary*)dict
{
    float x = [[dict objectForKey:[NSString stringWithFormat: @"%@@0", name]] floatValue];
    float y = [[dict objectForKey:[NSString stringWithFormat: @"%@@1", name]] floatValue];
    float w = [[dict objectForKey:[NSString stringWithFormat: @"%@@2", name]] floatValue];
    float h = [[dict objectForKey:[NSString stringWithFormat: @"%@@3", name]] floatValue];
    return CGRectMake(x, y, w,h);
}

In this example, I’m using stringWithFormat: in a simple way. To read four CGRect values for the rect ‘frame’ from the dictionary, it creates the keys [email protected], [email protected], [email protected], and [email protected] Because of the way my app works, I call stringWithFormat: to create strings like this a LOT. In complex situations, to the tune of 20,000x a second.

I was using Instruments to identify bottlenecks in my code and quickly discovered that stringWithFormat: was responsible for more than 40% of the time spent in the run loop. In an attempt to optimize, I switched to sprintf instead of stringWithFormat. The result was incredible. The code below is nearly 10x faster, and made key creation a negligible task:

1
2
3
4
5
6
7
8
- (NSString*)keyForValueAtIndex:(int)index inPropertySet:(NSString*)name
{
        // the following code just creates %@@%d  - but it's faster than stringWithFormat: by a factor of 10x.
        char cString[25];
        sprintf (cString, "@%d", ii);
        NSString* s = [[[NSString alloc] initWithUTF8String:cString] autorelease];
        return [name stringByAppendingString: s];
}

It’s worth mentioning that I’ve refactored the app even more—to completely avoid saving structs this way (since NSValue is uh… an obvious solution), but I felt like it was worth posting this anyway, since you might not be able to refactor in the way I did.