лучший способ реализовать читаемый регистр переключателя со строками в объекте-c?

В других динамических языках, таких как ruby, javascript и т. Д., Вы можете просто сделать это:

switch(someString) {
    case "foo":
       //do something;
       break;
    case "bar":
       // do something else;
       break;
    default:
       // do something by default;
}

В объекте-c, поскольку он очень похож на язык c, вы не можете этого сделать. Моя лучшая практика для этого:

#import "CaseDemo.h"

#define foo 1
#define bar 2

static NSMutableDictionary * cases;

@implementation CaseDemo

- (id)init 
{
    self = [super init];
    if (self != nil) {
        if (cases == nil) {
            // this dict can be defined as a class variable
            cases = [[NSMutableDictionary alloc] initWithCapacity:2];
            [cases setObject:[NSNumber numberWithInt:foo] forKey:@"foo"];
            [cases setObject:[NSNumber numberWithInt:bar] forKey:@"bar"];
        }
    }
    return self;
}

- (void) switchFooBar:(NSString *) param {
    switch([[cases objectForKey:param] intValue]) {
        case foo:
            NSLog(@"its foo");
            break;
        case bar:
            NSLog(@"its bar");
            break;
        default: 
            NSLog(@"its default");
            break;
    }
}
@end

Вроде бы нормально, но #define делает foo и bar зарезервированными словами, и я не могу использовать их в своем коде. Если я заменю константы определения константами класса, эта проблема будет устранена, потому что в других классах я должен использовать MyClassName перед именем константы. Но как я могу минимизировать выделение объектов для этой простой задачи? У кого-то есть "лучшая практика" для этого?

РЕДАКТИРОВАТЬ: Моя лучшая практика для этого:

#import "CaseDemo.h"

#define foo 1
#define bar 2

static NSMutableDictionary * cases;

@implementation CaseDemo

- (id)init 
{
    self = [super init];
    if (self != nil) {
        if (cases == nil) {
            // this dict can be defined as a class variable
            cases = [[NSMutableDictionary alloc] initWithCapacity:2];
            [cases setObject:[NSNumber numberWithInt:foo] forKey:@"foo"];
            [cases setObject:[NSNumber numberWithInt:bar] forKey:@"bar"];
        }
    }
    return self;
}

- (void) switchFooBar:(NSString *) param {
    switch([[cases objectForKey:param] intValue]) {
        case foo:
            NSLog(@"its foo");
            break;
        case bar:
            NSLog(@"its bar");
            break;
        default: 
            NSLog(@"its default");
            break;
    }
}
@end

Вроде бы нормально, но #define делает foo и bar зарезервированными словами, и я не могу использовать их в своем коде. Если я заменю константы определения константами класса, эта проблема будет устранена, потому что в других классах я должен использовать MyClassName перед именем константы. Но как я могу минимизировать выделение объектов для этой простой задачи? У кого-то есть "лучшая практика" для этого?

РЕДАКТИРОВАТЬ: Моя лучшая практика для этого:

#import "CaseDemo.h"

#define foo 1
#define bar 2

static NSMutableDictionary * cases;

@implementation CaseDemo

- (id)init 
{
    self = [super init];
    if (self != nil) {
        if (cases == nil) {
            // this dict can be defined as a class variable
            cases = [[NSMutableDictionary alloc] initWithCapacity:2];
            [cases setObject:[NSNumber numberWithInt:foo] forKey:@"foo"];
            [cases setObject:[NSNumber numberWithInt:bar] forKey:@"bar"];
        }
    }
    return self;
}

- (void) switchFooBar:(NSString *) param {
    switch([[cases objectForKey:param] intValue]) {
        case foo:
            NSLog(@"its foo");
            break;
        case bar:
            NSLog(@"its bar");
            break;
        default: 
            NSLog(@"its default");
            break;
    }
}
@end

Вроде бы нормально, но #define делает foo и bar зарезервированными словами, и я не могу использовать их в своем коде. Если я заменю константы определения константами класса, эта проблема будет устранена, потому что в других классах я должен использовать MyClassName перед именем константы. Но как я могу минимизировать выделение объектов для этой простой задачи? У кого-то есть "лучшая практика" для этого?

РЕДАКТИРОВАТЬ: Приведенный ниже код - это то, что я хотел сделать, но получить значения перечисления или #define немного неудобно. Потому что я создал приложение, у которого есть только ввод, где я могу написать строку, чтобы получить этот хеш, вернуться к xcode и установить значения для перечислений. Итак, моя проблема в том, что я не могу сделать это во время выполнения из-за основного поведения оператора switch case ... Или, если я сделаю это с помощью этого способа NSDictionary -> у него будет много накладных расходов по сравнению с этим решением.

#import "CaseDemo.h"

typedef enum {
    foo = 1033772579,
    bar = -907719821
} FooBar;

unsigned int APHash(NSString* s)
{
    const char* str = [s UTF8String];
    unsigned int len = [s length];    

    unsigned int hash = 0xAAAAAAAA;
    unsigned int i    = 0;

    for(i = 0; i < len; str++, i++)
    {
        hash ^= ((i & 1) == 0) ? (  (hash <<  7) ^ (*str) * (hash >> 3)) :
        (~((hash << 11) + ((*str) ^ (hash >> 5))));
    }

    return hash;
}

@implementation CaseDemo


- (void) switchFooBar:(NSString *) param {
    switch(APHash(param)) {
        case foo:
            NSLog(@"its foo");
            break;
        case bar:
            NSLog(@"its bar");
            break;
        default: 
            NSLog(@"its default");
            break;

    }
}

@end 

ПРИМЕЧАНИЕ: хеш-функция может быть определена в другом месте в общем пространстве имен, чтобы использовать ее где угодно, обычно я создаю Utils.h или Common.h для такого рода вещей.

ПРИМЕЧАНИЕ2: В "реальном" слово «нам нужно использовать некоторую криптографическую хеш-функцию, но теперь я использовал алгоритм Араша Партоу, чтобы упростить пример.

Итак, мой последний вопрос: Есть ли способ как-то оценить эти значения с помощью препроцессора? Думаю нет, а может? : -)

Что-то вроде:

// !!!!!! I know this code is not working, I don't want comments about "this is wrong" !!!!
// I want a solution to invoke method with preprocessor, or something like that. 
typedef enum {
        foo = APHash(@"foo"),
        bar = APHash(@"bar")
    } FooBar;

ОБНОВЛЕНИЕ : Я нашел "возможно решение", но похоже, работает только с g ++ 4.6>. обобщенные константные выражения могут сделать это за меня. Но я все еще тестирую ...

15
задан 13 revs 24 May 2011 в 19:27
поделиться