Switch with NSString
Recently, i.e. yesterday, I was asked whether you can do a switch() with an NSString, like this:
NSString *myString = ...;
switch(myString)
{
case @"foo":
[...]
break;
case @"bar":
[...]
break;
[...]
default:
[...]
break;
}
The correct answer is first yes, second no and third kind of yes.
First of all, an NSString is always a pointer, and that means it’s an integer. So is an @""
-string, mainly due to the fact that it’s an NSString as well. Comparing the two is entirely legal. Usually, you don’t want to do that, though. You don’t want to know whether these are the same objects, but whether they contain the same text. That doesn’t work with switch, so you ned the horribly infamous:
if ([myString isEqual:@"foo"])
{
[...]
}
else if ([myString isEqual:@"bar"])
{
[...]
}
[...]
else
{
[...]
}
If you said that this sucked then I’d tell you to mind your language, but otherwise I’d agree.
There’s a trick. I don’t like it, but it works, and does not rely on anything that’s not in the specifications. Indeed, I’ve found that in general, it works even faster. The problem is that that it’s ugly and maintenance is difficult. Let’s start.
NSArray *testArray = [NSArray arrayWithObjects:@"foo", @"bar", [...], nil];
switch([testArray indexOfObject:myString])
{
case 0: // foo
[...]
break;
case 1: // bar
[...]
break;
[...]
default:
[...]
break;
}
So we reintroduce the switch by looking up what index our string has in a known list. This is entirely legal, but there are some problems with this approach:
- There’s no obvious relation between a string and it’s index, so you’ll always have to write a comment noting just what exactly gets matched in every case.
- Deleting elements is rather difficult. If you’d want to no longer match against
@"foo"
, for example, you’d have to renumber the case for@"bar"
and all later ones. Of course you could just leave it in and leave case 0 empty or combine it with the default case, but that’s dead code and dead code is never good. - While legal, it’s not elegant. It follows the language of the specification but not it’s intent. You’re not actually supposed to create an array just to get an index.
I’ve said above that this tends to be faster than the traditional if-else if-chain. Please note that this was measured some time ago. It can have changed. It can still change. But let’s be honest, if your performance depends on this, then you’re having bigger problems to begin with.
Final note: Should you use it? In case of doubt I’d say no, but there are cases where it greatly simplified my work. Just make sure you don’t ignore this technique’s problems when choosing.
Written on July 30th, 2008 at 10:19 pm