Switch mit NSString
Kürzlich (sprich gestern) wurde ich gefragt, ob man mit NSString switch() machen kann, also z.B.:
NSString *myString = ...;
switch(myString)
{
case @"foo":
[...]
break;
case @"bar":
[...]
break;
[...]
default:
[...]
break;
}
Die korrekte Antwort darauf lautet erst mal ja, dann nein, dann ja mit Hintertür.
Erst mal ist ein NSString immer ein Pointer, und damit ein Integer. Ein @""
-String ist letztlich genau das gleiche, also kann man die beiden durchaus miteinander vergleichen. Im Normalfall braucht man aber keine Pointer-Gleichheit, sondernd, dass die Objekte gleich sind. So etwas geht mit switch nicht, also braucht man die weitaus unbeliebtere Konstruktion:
if ([myString isEqual:@"foo"])
{
[...]
}
else if ([myString isEqual:@"bar"])
{
[...]
}
[...]
else
{
[...]
}
Mist, oder?
Es gibt einen Trick. Ich mag ihn nicht, aber er funktioniert, entspricht genau den Apple-Spezifikationen und läuft nach meinen Tests sogar deutlich schneller. Das Problem an der Sache ist, dass das ganze sehr, sehr hässlich ist, und dass Wartung teilweise schwierig wird. Aber gut, fangen wir an.
NSArray *testArray = [NSArray arrayWithObjects:@"foo", @"bar", [...], nil];
switch([testArray indexOfObject:myString])
{
case 0: // foo
[...]
break;
case 1: // bar
[...]
break;
[...]
default:
[...]
break;
}
Wir führen hier also das Switch wieder ein, in dem wir den Index des Strings in einer bekannten Liste bestimmen. Das ist völlig legal, es gibt aber einige Probleme damit:
- Es gibt keinen offensichtlichen Zusammenhang zwischen String und Index, daher ist es sehr wichtig, immer im Kommentar zu vermerken, welcher String denn nun wozu gehört.
- Löschen von Elementen ist erstaunlich schwierig. Wenn wir zum Beispiel hier
@"foo"
löschen wollen, müssen wir alle Elemente dahinter umnummerieren. Natürlich können wir Fall 0 auch einfach leer lassen oder mit demdefault:
-Fall zusammenlegen, aber das ist toter Code, und toter Code ist schlechter Code. - Der ganze Haufen ist nicht elegant. Ein Array erstellen nur um einen Index zu finden? So was macht einfach keinen Spaß.
Ich habe oben gesagt, dass die Performance dieses Codes besser ist als die der traditionellen if-else if-Kette. Diese Messung liegt lange zurück, dass kann sich seither durchaus geändert haben und kann sich in Zukunft auch durchaus nicht ändern. Aber mal ehrlich, wenn die Performance eines Programmes wirklich von der Effizienz eines solchen String-Vergleiches abhängt, dann hat man sowieso ganz andere Probleme.
Fazit: Sollte man dies verwenden? Im Zweifelsfalle Nein, würde ich sagen. Ich habe aber festgestellt, dass es mein Leben in einigen Sonderfällen stark vereinfacht hat. Auf jeden Fall sollte man niemals die Probleme dieser Technik ignorieren.
Geschrieben am 30. Juli 2008 um 22:19