0

I have a string I want to parse and return an equivalent enum. I need to use the enum type elsewhere, and I think I like how I'm defining it. The problem is that I don't know a good way to check the string against the enum values without being redundant about the order of the enums.

Is there no option other than a big if/else?

typedef enum {
    ZZColorRed,
    ZZColorGreen,
    ZZColorBlue,
} ZZColorType;


- (ZZColorType)parseColor:(NSString *)inputString {
    // inputString will be @"red", @"green", or @"blue" (trust me)
    // how can I turn that into ZZColorRed, etc. without
    // redefining their order like this?

    NSArray *colors = [NSArray arrayWithObjects:@"red", @"green", @"blue", nil];
    return [colors indexOfObject:inputString];
}

In Python, I'd probably do something like the following, although to be honest I'm not in love with that either.

## maps  url text -> constant string
RED_CONSTANT = 1
BLUE_CONSTANT = 2
GREEN_CONSTANT = 3

TYPES = {
    'red': RED_CONSTANT,
    'green': GREEN_CONSTANT,
    'blue': BLUE_CONSTANT,
}

def parseColor(inputString):
    return TYPES.get(inputString)

ps. I know there are color constants in Cocoa, this is just an example.

zekel
  • 9,227
  • 10
  • 65
  • 96

3 Answers3

3

try this: Map enum to char array

Pseudo code.. untested.

int lookup(const char* str) {
    for(name = one; name < NUMBER_OF_INPUTS; name++) {
        if(strcmp(str, stats[name]) == 0) return name;
    }
    return -1;
}

A more objective-c'ish version of the code could be:

// build dictionary
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
for(i=0; i<number_of_strings; i++) {
    [dict setObject:[NSNumber numberWithInteger:i] forKey:[NSString stringWithUTF8String:names[i]]];
}

// elsewhere... lookup in dictionary
id obj = [dict objectForKey:name];
if(obj) return [obj intValue];
return -1;
neoneye
  • 50,398
  • 25
  • 166
  • 151
  • That's not so bad. I can tack on one more enum value ZZColorMax so I don't have to hardcode number-of-strings. – zekel May 17 '10 at 23:05
0

I was never satisfied with any of the suggestions. (But I appreciate the effort that went into them.) I tried a few of them but they didn't feel good or were error-prone in practice.

I ended up created a custom dictionary to map integers to strings which feels a lot better because it's Cocoa through and through. (I didn't subclass NSDictionary in order to make it harder to misuse.)

@interface ZZEnumDictionary : NSObject {
    NSMutableDictionary *dictionary;
}

+ (id)dictionary;
+ (id)dictionaryWithStrings:(id)firstString, ...;
- (NSString *)stringForInt:(NSInteger)intEnum;
- (NSInteger)intForString:(NSString *)stringEnum;
- (BOOL)isValidInt:(NSInteger)intEnum;
- (BOOL)isValidString:(NSString *)stringEnum;
- (BOOL)stringEquals:(NSString *)stringEnum intEnum:(NSInteger)intEnum;
- (BOOL)setContainsString:(NSSet *)set forInt:(NSInteger)intEnum;
- (NSArray *)allStrings;
@end

@interface ZZEnumDictionary ()
- (void)setInt:(NSInteger)integer forString:(NSString *)string;
@end
zekel
  • 9,227
  • 10
  • 65
  • 96
0

This has already been answered: Converting between C enum and XML

Basically, you wind up defining corresponding strings when you define your enum, and then you use a category on NSArray so that you can do this:

static NSArray* colorNamesArray = [[NSArray alloc] initWithObjects:colorNames];
//colorNames is a nil-terminated list of string literals #defined near your enum
NSString* colorName = [colorNamesArray stringWithEnum:color];
//stringWithEnum: is defined with a category

Sure, the #define is a little ugly, but the code above, which is what you'll work with most of the time, is actually pretty clean.

Community
  • 1
  • 1
andyvn22
  • 14,696
  • 1
  • 52
  • 74