Objective-C può accendere NSString?


166

C'è un modo più intelligente per riscriverlo?

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
No, switch funziona solo su tipi int / bool / char / etc.
vestito il

questa domanda è in qualche modo simile a questo scritto solo un'ora fa ( stackoverflow.com/questions/8161319/... )
Michael Dautermann

3
Esistono diversi modi alternativi per farlo. Ad esempio, caricare un array con i valori e cercare una corrispondenza nell'array. Nessuno estremamente efficiente, ma riducono la duplicazione del codice.
Hot Licks

4
Come nota a margine, il nuovo linguaggio di Apple (Swift) ora consente di confrontare le stringhe in un'istruzione switch!
Jaredsmith,

4
Passa a Swift;)
tothemario

Risposte:


147

Sfortunatamente non possono. Questo è uno degli utilizzi migliori e più ricercati delle istruzioni switch, quindi speriamo che saltino sul carro (ora) Java (e altri)!

Se stai facendo nomi di carte, forse assegna a ciascun oggetto carta un valore intero e accendilo. O forse un enum, che è considerato come un numero e può quindi essere attivato.

per esempio

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

} CardType;

Fatto in questo modo, l'asso sarebbe uguale al caso 0, due al caso 1, ecc.


4
@abbood Per ulteriori informazioni su enum, vedere la pubblicazione NS_ENUM & NS_OPTIONS di Mattt Thompson.
Basil Bourque,

@abbood cosa dovrebbe significare il tuo commento? Sembra che questa sia una cattiva risposta, ma mi sembra ok. Potresti spiegare ?
Alan Andrade,

A quanto ho capito, CardTypenon può essere uguale a nessun allegato, @""ad esempio:[CardType isEqualToString:@"Three"]
Adromil Balais,

120

È possibile impostare un dizionario di blocchi, in questo modo:

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

Per avere una sezione "predefinita", sostituisci l'ultima riga con:

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

Speriamo che Apple insegnerà a "cambiare" alcuni nuovi trucchi.


35
Non so dire se è davvero brutto o davvero bello. Non avrei mai pensato di farlo, grazie.
fine

2
Mentre stiamo facendo cose strane come questa, perché non creare la tua classe che avvolge un NSDictionary pieno di chiavi NSString per gli oggetti blocco e quindi fornisce un altro blocco per i casi predefiniti? Puoi persino avere il supporto per la notazione dei pedici.
ArtOfWarfare il

1
Punti extra se si crea una sottoclasse NSDictionary proprio per questo: P
CommaToast

2
Sotto il cofano, questo è il modo in cui C # lo fa per le istruzioni switch di grandi dimensioni.
Hank Schultz,

78

Per me, un bel modo semplice:

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
Mi piace questo. Risponde alle esigenze della maggior parte alla ricerca di una risposta a questo problema, non richiede molto più digitando di un interruttore simile che prenderebbe JavaScript, ed è leggibile dall'uomo.
ew parris

4
Non confronterei questo hack con lo switch JS. Cosa succede se il programmatore successivo aggiunge un elemento tra item1 e item2? Troppo potenziale per l'introduzione di bug
Aras

è un bel trucco però, quindi ti do il pollice in alto per lo sforzo :)
Aras

@Aras Se il programmatore successivo deve aggiungere una nuova voce, la aggiunge alla fine dell'array con una nuova istruzione case alla fine per gestirla. Quindi @ "item0" può essere aggiunto dopo @ "item3" nell'array, quindi aggiungere un caso 3: per gestirlo.
sbonkosky,

1
Mi piace assolutamente la tua strada. È molto pulito. Sto scrivendo la categoria e devo restituire UIColor mentre ho una stringa con me.
Alix,

11

Sfortunatamente, le istruzioni switch possono essere utilizzate solo su tipi primitivi. Tuttavia, hai alcune opzioni usando le raccolte.

Probabilmente l'opzione migliore sarebbe quella di memorizzare ogni valore come voce in un 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

Un po 'in ritardo, ma per chiunque in futuro sono stato in grado di farlo funzionare per me

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

Questo è interessante. Puoi approfondire di più?
Chen Li Yong,

6

Ecco il modo più intelligente di scriverlo. E 'di utilizzare un NSNumberFormatternello "stile spell-out" :

NSString *cardName = ...;

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

Nota che il formattatore dei numeri vuole che la stringa sia minuscola, quindi dobbiamo farlo da soli prima di passarla al formatter.


5

Ci sono altri modi per farlo, ma switchnon è uno di questi.

Se hai solo poche stringhe, come nel tuo esempio, il codice che hai va bene. Se hai molti casi, puoi archiviare le stringhe come chiavi in ​​un dizionario e cercare il valore corrispondente:

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

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

4

DI FAR .. il mio componente aggiuntivo "ObjC" PREFERITO è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

E funziona anche con non stringhe, TROPPO ... anche in loop!

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.

Soprattutto, ci sono così pochi {...}", :" e ()"s"


3

Objective-c non è diverso da c in questo aspetto, può solo accendere ciò che c può (e il def di preproc è come NSInteger, NSUInteger, dato che alla fine sono semplicemente scritti in un tipo integrale).

Wikipedia:

sintassi c :

L'istruzione switch fa sì che il controllo venga trasferito a una delle diverse istruzioni in base al valore di un'espressione, che deve avere un tipo integrale .

Tipi integrali :

Nell'informatica, un numero intero è un dato del tipo di dati integrale, un tipo di dati che rappresenta un sottoinsieme finito degli interi matematici. I tipi di dati integrali possono avere dimensioni diverse e possono contenere o meno valori negativi.


2

Sono un po 'in ritardo alla festa, ma per rispondere alla domanda come indicato , c'è un modo più intelligente:

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

Nota che indexOfObjectcercherà la partita usando isEqual:, esattamente come nella domanda.


2

Basandosi sull'idea di @Graham Perks pubblicata in precedenza, ho progettato una classe semplice per rendere l'accensione delle stringhe abbastanza semplice e pulita.

@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

Lo useresti così:

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

Il blocco corretto verrà eseguito in base alla stringa.

Saggia per questa soluzione


0

Non posso commentare la risposta di cris sulla risposta di @Cris, ma vorrei dire che:

C'è una LIMITAZIONE per il metodo di @ cris:

typedef enum non prenderà valori alfanumerici

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

} CardType;

Quindi eccone un altro:

Link Stack over flow Vai a questa risposta per l'utente "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;
    }
}

Goditi la programmazione .....

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.