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.