tags:

views:

182

answers:

3

Hi, I need to compare an enum as a whole to one string, so the whole contents of the enum is checked.

Wanted something like:

NSString *colString = [[NSString aloc] initWithString:@"threeSilver"];


typedef enum {
oneGreen,
twoBlue, 
threeSilver
}numbersAndColours;

if (colString == numbersAndColours) {
//Do cool stuff
}

But obviously I can't do that, maybe a struct... sorry, I'm new to C please help?

BTW: I know NSString isn't C, but figured this question was more C, than Obj-C.

Thanks

+1  A: 

C, ObjC and C++ don't support that directly, you have to create an explicit mapping.

Example using plain C:

typedef struct { 
    numbersAndColours num;
    const char* const str;
} entry;

#define ENTRY(x) { x, #x }

numberAndColours toNum(const char* const s) {
    static entry map[] = {
        ENTRY(oneGreen),
        ENTRY(twoBlue),
        ENTRY(threeSilver)
    }; 
    static const unsigned size = sizeof(map) / sizeof(map[0]);

    for(unsigned i=0; i<size; ++i) {
         if(strcmp(map[i].str, s) == 0) 
             return map[i].num;
    }

    return -1; // or some other value thats not in the enumeration
}

#undef ENTRY

// usage:

assert(toNum("oneGreen") == oneGreen); 
assert(toNum("fooBar") == -1);

Basic Objective-C approach:

#define ENTRY(x) [NSNumber numberWithInt:x], @#x

NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys:
    ENTRY(oneGreen),
    ENTRY(twoBlue),
    ENTRY(threeSilver),
    nil];

#undef ENTRY

if([dict objectForKey:@"oneGreen"]) {
    // ... do stuff 
}
Georg Fritzsche
+1 for use of #define ENTRY(x) { x, #x }, I would do this, but as an Obj-C category so it's a little easier on the eyes when in use
slf
The original question asked more for the general "C"-ish approach, for Objective-C specifically i'd write a more convenient version of course :)
Georg Fritzsche
Nice touch on the Objective-C approach. That would allow you to maintain the number as well as the string. However, the keys and values added into the dictionary will be over-retained.
dreamlax
Also, no need to create a string at runtime, you could use a constant string as the key, just use `@#x`.
dreamlax
I guess its gotten a bit too late here, i even missed the parameter to `objectForKey:`.
Georg Fritzsche
+2  A: 

In C you'd have to write a function for that. It would essentially be a switch statement.

char* colour_of(enum numbersAndColours c)
{
    switch( c ) {
    case oneGreen:
        return "oneGreen";
        break;
    case twoBlue:
        return "twoBlue";
        break;
    /* ... */
    default:
        return "donno";
    }
}

You can use the function then like so:

{
    char* nac;
    nac = colour_of(numbersAndColours);
    if( strncmp(colString, nac, colStringLen) == 0 )
        /* ... */
}

If colString doesn't match any of the enum elements it won't match numbersAndColours. There is no need to compare it against all of the elements.

wilhelmtell
Could you enlighten me? Maybe some sample code? Thanks so so much!
Niceguy
+1  A: 

I'm not sure I understand what you're trying to achieve, but you may like to have a look into NSSet. It seems like you want your program to do cool stuff if the colString is a particular value.

NSSet *numbersAndColors = [NSSet setWithObjects:@"oneGreen", @"twoBlue", @"threeSilver", nil];
NSString *colString = [[NSString alloc] initWithString:@"threeSilver"];

if ([numbersAndColors containsObject:colString])
{
    // do cool stuff
}

An NSSet is faster than an NSArray when you just want to know whether a particular object exists, but one important aspect about an NSSet is that it does not maintain the order of objects. It is typically used when you don't care about the order and just want to test when an object exists in a set.

dreamlax
But ... That's in runtime... Isn't it a bit wasteful (forgive the pun)?
wilhelmtell
For constant, repeated lookup it would be better to place the set's creation in an initialisation method so that the same set is used over and over. I just provided it in the same scope as an example.
dreamlax
Well, I meant that the OP wanted the string value of enum elements. You know them all at compile time, so why not have this job done at compile-time? What advantage does a set have over a function? Recall this is a read-only operation, because you can't add enum elements at runtime.
wilhelmtell
Oh, I must have misunderstood then. I thought he wanted to ensure that his `colString` (wherever it was sourced from) matched either `"oneGreen"`, `"twoBlue"`, or `"threeSilver"`.
dreamlax
Actually i wanted to ensure colString was matching one of the three values. "oneGreen" etc etc... this is perfect ;)
Niceguy
Ok, @Niceguy, now you have me confused. I thought you wanted to check if a given string matches the string representation of an enum value.
wilhelmtell