Чи може Objective-C увімкнути NSString?


166

Чи є більш розумний спосіб переписати це?

if ([cardName isEqualToString:@"Six"]) {
    [self setValue:6];
} else if ([cardName isEqualToString:@"Seven"]) {
    [self setValue:7];
} else if ([cardName isEqualToString:@"Eight"]) {
    [self setValue:8];
} else if ([cardName isEqualToString:@"Nine"]) {
    [self setValue:9];
} 

1
Ні, перемикач працює лише на типи int / bool / char / тощо.
чон

це питання дещо схожий на цей публікується тільки годину назад ( stackoverflow.com/questions/8161319 / ... )
Майкл Dautermann

3
Існує кілька альтернативних способів зробити це. Наприклад, завантажте масив зі значеннями та шукайте відповідність у масиві. Жоден з них не дуже ефективний, але вони зменшують дублювання коду.
Гарячі лизання

4
В якості додаткового зауваження, нова мова Apple (Swift) тепер дозволяє порівнювати рядки в операторі комутатора!
Джаредсміт

4
Switch to Swift;)
tothemario

Відповіді:


147

На жаль, вони не можуть. Це одне з найкращих і найбільш затребуваних використання операторів комутації, тому, сподіваємось, вони скачуть на (тепер) Java (та інших) смузі!

Якщо ви робите назви карт, можливо, призначте кожному об'єкту картки ціле значення та увімкніть це. Або, можливо, перерахунок, який розглядається як число, і тому його можна переключити.

напр

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

} CardType;

Зроблено таким чином, туз буде дорівнює випадку 0, два як випадку 1 тощо.


4
@abbood Для отримання додаткової інформації про enum дивіться публікацію NS_ENUM & NS_OPTIONS Метта Томпсона.
Василь Бурк

@abbood, що має означати ваш коментар? Здається, це погана відповідь, але мені здається ОК. Чи можете ви пояснити?
Алан Андраде

Як я розумію, CardTypeне може бути рівним жоден доданий, @""наприклад:[CardType isEqualToString:@"Three"]
Адроміль Балай

120

Ви можете встановити словник блоків, наприклад, такий:

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

Щоб мати розділ "за замовчуванням", замініть останній рядок на:

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

Сподіваємось, Apple навчить "перемикати" кілька нових хитрощів.


35
Я не можу сказати, чи справді це неприємно чи дуже здорово. Ніколи б не думав це робити, дякую.
endy

2
Хоча ми робимо такі дивні речі, як це, чому б не зробити свій власний клас, який обгортає NSD Dictionary, повний ключів NSString для блокових об'єктів, а потім надає ще один блок для випадків за замовчуванням? Ви навіть можете підтримувати його підпискою.
ArtOfWarfare

1
Додаткові бали, якщо ви складаєте підклас NSDictionary саме для цього: P
CommaToast

2
Під кришкою це так, як C # робить це для великих операторів комутації.
Ганк Шульц

78

Приємний простий спосіб для мене:

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;
}

1
Мені подобається це. Він відповідає потребам більшості шукає відповіді на цю проблему, не вимагає набагато більше типізації, ніж аналогічний перемикач, який би потребував javascript, і це читається людиною.
ew parris

4
Я б не порівнював цей злом з перемикачем JS. Що станеться, якщо наступний програміст додасть елемент між item1 та item2? Занадто великий потенціал для введення помилок
Арас

це хороший хак, хоча я даю вам великі пальці за зусилля :)
Aras

@Aras Якщо наступному програмісту потрібно додати новий запис, він додасть його до кінця масиву з новим виписком регістру в кінці, щоб обробити його. Тож @ "item0" можна додати після @ "item3" в масив, а потім додати випадок 3: для обробки.
sbonkosky

1
Мені абсолютно подобається твій шлях. Це дуже акуратно. Я пишу категорію і мені потрібно повернути UIColor, поки у мене є рядок.
Алікс

11

На жаль, оператори перемикання можуть використовуватися лише на примітивних типах. Однак у вас є кілька варіантів використання колекцій.

Напевно, найкращим варіантом було б зберігати кожне значення як запис у 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]];

8

Трохи запізнюючись, але для будь-кого в майбутньому я зміг змусити це працювати для мене

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

Це цікаво. Чи можете ви детальніше розробити?
Чень Лі Йонг

6

Ось більш розумний спосіб написати це. Це використовувати NSNumberFormatterв "стилі написання" :

NSString *cardName = ...;

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

Зауважте, що форматник чисел хоче, щоб рядок був зменшений, тому ми повинні зробити це самостійно, перш ніж передавати його у форматер.


5

Є й інші способи зробити це, але switchце не один із них.

Якщо у вас є лише кілька рядків, як у вашому прикладі, код у вас є нормальним. Якщо у вас багато випадків, ви можете зберігати рядки як ключі у словнику та шукати відповідне значення:

NSDictionary *cases = @{@"Six" : @6,
                        @"Seven" : @7,
                        //...
                       };

NSNumber *value = [cases objectForKey:cardName];
if (value != nil) {
    [self setValue:[value intValue]];
}

4

ЗА ДОПОМОГОМ .. мій ПОДАВНИЙ "Додаток ObjC"ObjectMatcher

objswitch(someObject)
    objcase(@"one") { // Nesting works.
        objswitch(@"b")
            objcase(@"a") printf("one/a");
            objcase(@"b") printf("one/b");
            endswitch // Any code can go here, including break/continue/return.
    }
    objcase(@"two") printf("It's TWO.");  // Can omit braces.
    objcase(@"three",     // Can have multiple values in one case.
        nil,              // nil can be a "case" value.
        [self self],      // "Case" values don't have to be constants.
        @"tres", @"trois") { printf("It's a THREE."); }
    defaultcase printf("None of the above."); // Optional default must be at end.
endswitch

І це працює з не рядками, TOO ... в циклі, навіть!

for (id ifNumericWhatIsIt in @[@99, @0, @"shnitzel"])
    objswitch(ifNumericWhatIsIt)
        objkind(NSNumber)  printf("It's a NUMBER.... "); 
        objswitch([ifNumericWhatIsIt stringValue])
            objcase(@"3")   printf("It's THREE.\n"); 
            objcase(@"99")  printf("It's NINETY-NINE.\n"); 
            defaultcase     printf("some other Number.\n");
       endswitch
    defaultcase printf("It's something else entirely.\n");
endswitch

It's a NUMBER.... It's NINETY-NINE.
It's a NUMBER.... some other Number.
It's something else entirely.

Найкраще, що так мало {...}'s, :' і ()'s


3

Objective-c нічим не відрізняється від c у цьому аспекті, він може перемикати лише те, що може (і препрок дефіс подібний до NSInteger, NSUInteger, оскільки вони в кінцевому підсумку просто вводяться до цілісного типу).

Вікіпедія:

c синтаксис :

Оператор перемикання призводить до того, що контроль переноситься на один із декількох висловлювань залежно від значення виразу, яке повинно мати цілісний тип .

Цілісні типи :

В інформатиці ціле число - це дата цілісного типу даних, тип даних, який представляє деяку кінцеву підмножину математичних цілих чисел. Інтегральні типи даних можуть бути різного розміру і можуть містити негативні значення.


2

Я запізнююся на вечірку, але щоб відповісти на заявлене запитання , є більш розумний спосіб:

NSInteger index = [@[@"Six", @"Seven", @"Eight", @"Nine"] indexOfObject:cardName];
if (index != NSNotFound) [self setValue: index + 6];

Зауважте, що indexOfObjectбуде шукати матч isEqual:саме так, як у питанні.


2

Спираючись на ідею @Graham Perks, опубліковану раніше, створив простий клас, щоб зробити перехід на рядки досить простим і чистим.

@interface Switcher : NSObject

+ (void)switchOnString:(NSString *)tString
                 using:(NSDictionary<NSString *, CaseBlock> *)tCases
           withDefault:(CaseBlock)tDefaultBlock;

@end

@implementation Switcher

+ (void)switchOnString:(NSString *)tString
                 using:(NSDictionary<NSString *, CaseBlock> *)tCases
           withDefault:(CaseBlock)tDefaultBlock
{
    CaseBlock blockToExecute = tCases[tString];
    if (blockToExecute) {
        blockToExecute();
    } else {
        tDefaultBlock();
    }
}

@end

Ви б використовували це так:

[Switcher switchOnString:someString
                   using:@{
                               @"Spades":
                               ^{
                                   NSLog(@"Spades block");
                               },
                               @"Hearts":
                               ^{
                                   NSLog(@"Hearts block");
                               },
                               @"Clubs":
                               ^{
                                   NSLog(@"Clubs block");
                               },
                               @"Diamonds":
                               ^{
                                   NSLog(@"Diamonds block");
                               }
                           } withDefault:
                               ^{
                                   NSLog(@"Default block");
                               }
 ];

Правильний блок буде виконуватися відповідно до рядка.

Суть цього рішення


0

Я не можу коментувати відповідь Кріса на відповідь @Cris, але я хотів би сказати це:

Існує ОБМЕЖЕННЯ для методу @ cris:

typedef enum не буде приймати буквено-цифрові значення

typedef enum
{
  12Ace, 23Two, 23Three, 23Four, F22ive ... Jack, Queen, King

} CardType;

Отже ось ще один:

Стек стеку за потоком Перейти до відповіді цього користувача "user1717750"


-1
typedef enum
{
    Six,
    Seven,
    Eight
} cardName;

- (void) switchcardName:(NSString *) param {
    switch([[cases objectForKey:param] intValue]) {
        case Six:
            NSLog(@"Six");
            break;
        case Seven:
            NSLog(@"Seven");
            break;
        case Eight:
            NSLog(@"Eight");
            break;
        default: 
            NSLog(@"Default");
            break;
    }
}

Насолоджуйтесь кодування .....

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.