One of the nice things Objective-C inherited from C is the switch statement. If you have set different tags in all your menu items, you often find you can do things like:
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
switch ([menuItem action]) {
case 1:
...
case 2:
...
}
return YES;
}
Those tags have to be set in Interface Builder, and you probably will have an enum somewhere to use symbolic constants instead. However, the standard C switch() is restricted to integer values; you can’t switch on strings or selectors. So, if you don’t want tags and need to switch on the menu item’s selectors, you’ll have to do:
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
SEL action = [menuItem action];
if (action==@selector(firstAction:)) {
...
} else if (action==@selector(secondAction:)) {
...
} else...
return YES;
}
Bearable if you have two, or even four or five cases, but what if there are dozens? Or suppose you have to compare strings instead of selectors:
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
NSString* title = [menuItem title];
if ([title isEqualToString:@"firstTitle"]) {
...
} else if ([title isEqualToString:@"secondTitle"]) {
...
} else...
return YES;
}
Not that it’s recommendable, in practice, to compare menu item titles, but it’s a good example.
Well, there are other ways to make this more readable, or even more efficient. But here’s one neat way to convert a group of strings into integers for use in a switch(). First, let’s write an utility C function to do so:
NSUInteger CaseCodeForString(NSString* string) {
static NSArray* array = nil;
if (!array) {
array = [[NSArray alloc] initWithObjects:
@"zeroth string",
@"first string",
@"second string",
@"third string",
...
nil];
}
return [array indexOfObject:string];
}
Note the standard lazy allocate-once trick of declaring array static, initialize it to nil, and test before using. Anyway, this function will return 0 if you feed it @”zeroth string”, 1 for @”first string” and so forth… and return NSNotFound if the string isn’t in the array. So you could, in our last example, do:
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem {
switch (CaseCodeForString([menuItem title])) {
case 0:
...
case 1:
...
}
return YES;
}
If there are many strings, this will be faster than a series of isEqualToString: calls; this is because NSArray uses a hash table to find the index of a particular object, and only goes into the actual string comparison if the two string’s -hash methods return the same value.
Leave a Comment