Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Objective-C switch on NSString?

Unfortunately they cannot. This is one of the best and most sought after utilizations of switch statements, so hopefully they hop on the (now) Java (and others) bandwagon!

If you are doing card names, perhaps assign each card object an integer value and switch on that. Or perhaps an enum, which is considered as a number and can therefore be switched upon.

e.g.

typedef enum{
  Ace, Two, Three, Four, Five ... Jack, Queen, King

} CardType;

Done this way, Ace would be be equal to case 0, Two as case 1, etc.


You could set up a dictionary of blocks, like this:

NSString *lookup = @"Hearts"; // The value you want to switch on

typedef void (^CaseBlock)();

// Squint and this looks like a proper switch!
NSDictionary *d = @{
    @"Diamonds": 
    ^{ 
        NSLog(@"Riches!"); 
    },
    @"Hearts":
    ^{ 
        self.hearts++;
        NSLog(@"Hearts!"); 
    },
    @"Clubs":
    ^{ 
        NSLog(@"Late night coding > late night dancing"); 
    },
    @"Spades":
    ^{ 
        NSLog(@"I'm digging it"); 
    }
};

((CaseBlock)d[lookup])(); // invoke the correct block of code

To have a 'default' section, replace the last line with:

CaseBlock c = d[lookup];
if (c) c(); else { NSLog(@"Joker"); }

Hopefully Apple will teach 'switch' a few new tricks.


For me, a nice easy way:

NSString *theString = @"item3";   // The one we want to switch on
NSArray *items = @[@"item1", @"item2", @"item3"];
int item = [items indexOfObject:theString];
switch (item) {
    case 0:
       // Item 1
       break;
    case 1:
       // Item 2
       break;
    case 2:
       // Item 3
       break;
    default:
       break;
}

Unfortunately, switch statements can only be used on primitive types. You do have a few options using collections, though.

Probably the best option would be to store each value as an entry in an NSDictionary.

NSDictionary *stringToNumber = [NSDictionary dictionaryWithObjectsAndKeys:
                                              [NSNumber numberWithInt:6],@"Six",
                                              [NSNumber numberWithInt:7],@"Seven",
                                              [NSNumber numberWithInt:8],@"Eight",
                                              [NSNumber numberWithInt:9],@"Nine",
                                              nil];
NSNumber *number = [stringToNumber objectForKey:cardName];
if(number) [self setValue:[number intValue]];

A bit late but for anyone in the future I was able to get this to work for me

#define CASE(str) if ([__s__ isEqualToString:(str)])
#define SWITCH(s) for (NSString *__s__ = (s); ; )
#define DEFAULT

Here is the more intelligent way to write that. It's to use an NSNumberFormatter in the "spell-out style":

NSString *cardName = ...;

NSNumberFormatter *nf = [[NSNumberFormatter alloc] init];
[nf setNumberStyle:NSNumberFormatterSpellOutStyle];
NSNumber *n = [nf numberFromString:[cardName lowercaseString]];
[self setValue:[n intValue]];
[nf release];

Note that the number formatter wants the string to be lowercased, so we have to do that ourselves before passing it in to the formatter.