Bisakah Objective-C mengaktifkan NSString?

166

Apakah ada cara yang lebih cerdas untuk menulis ulang ini?

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];
} 
James Raitsev
sumber
1
Tidak, sakelar hanya berfungsi pada tipe int / bool / char / etc.
chown
pertanyaan ini agak mirip dengan yang ini diposting hanya satu jam yang lalu ( stackoverflow.com/questions/8161319/… )
Michael Dautermann
3
Ada beberapa cara alternatif untuk melakukannya. Misalnya, memuat array dengan nilai-nilai dan mencari kecocokan dalam array. Tidak ada yang sangat efisien, tetapi mereka mengurangi duplikasi kode.
Hot Licks
4
Sebagai catatan tambahan, bahasa baru Apple (Swift) sekarang memungkinkan untuk membandingkan string dalam pernyataan switch!
jaredsmith
4
Beralih ke Swift;)
tothemario

Jawaban:

147

Sayangnya mereka tidak bisa. Ini adalah salah satu yang terbaik dan pemanfaatan yang paling dicari dari pernyataan switch, jadi semoga mereka naik kereta musik (sekarang) Java (dan lainnya)!

Jika Anda melakukan nama kartu, mungkin menetapkan setiap objek kartu nilai integer dan aktifkan itu. Atau mungkin enum, yang dianggap sebagai angka dan karenanya dapat diaktifkan.

misalnya

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

} CardType;

Dilakukan dengan cara ini, Ace akan sama dengan case 0, Two sebagai case 1, dll.

Chris
sumber
4
@abbood Untuk informasi lebih lanjut tentang enum, lihat posting NS_ENUM & NS_OPTIONS oleh Mattt Thompson.
Basil Bourque
@abbood, apa maksud komentar Anda? Kedengarannya seperti ini adalah jawaban yang buruk tetapi tampaknya tidak masalah bagi saya. Bisakah Anda jelaskan?
Alan Andrade
Seperti yang saya mengerti, CardTypetidak bisa sama dengan yang terlampir @""misalnya:[CardType isEqualToString:@"Three"]
Adromil Balais
120

Anda dapat mengatur kamus blok, seperti ini:

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

Untuk memiliki bagian 'default', ganti baris terakhir dengan:

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

Semoga Apple akan mengajarkan 'berganti' beberapa trik baru.

Graham Perks
sumber
35
Saya tidak tahu apakah ini benar-benar jahat atau keren. Tidak akan pernah berpikir untuk melakukan ini, terima kasih.
endy
2
Sementara kami melakukan hal-hal aneh seperti ini, mengapa tidak membuat kelas Anda sendiri yang membungkus NSDictionary yang penuh dengan kunci NSString untuk objek blok dan kemudian menyediakan blok lain untuk kasus default? Anda bahkan dapat memilikinya mendukung notasi subskrip.
ArtOfWarfare
1
Poin tambahan jika Anda membuat subkelas NSDictionary hanya untuk ini: P
CommaToast
2
Di bawah tenda, ini adalah cara C # melakukannya untuk pernyataan pergantian besar.
Hank Schultz
78

Bagi saya, cara mudah yang menyenangkan:

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;
}
sbonkosky
sumber
1
Saya suka ini. Ini menjawab kebutuhan sebagian besar mencari jawaban untuk masalah ini, tidak perlu lebih banyak mengetik daripada switch serupa akan mengambil javascript, dan itu dapat dibaca manusia.
ew parris
4
Saya tidak akan membandingkan retasan ini dengan saklar JS. Apa yang terjadi jika programmer berikutnya menambahkan item antara item1 dan item2? Terlalu banyak potensi untuk memperkenalkan bug
Aras
itu hack yang bagus, jadi saya berikan Anda acungan jempol untuk usaha :)
Aras
@ Aras Jika programmer berikutnya perlu menambahkan entri baru maka mereka akan menambahkannya ke akhir array dengan pernyataan kasus baru di akhir untuk menanganinya. Jadi @ "item0" dapat ditambahkan setelah @ "item3" dalam array, lalu tambahkan case 3: untuk menanganinya.
sbonkosky
1
Aku sangat suka caramu. Sangat rapi. Saya menulis kategori dan perlu mengembalikan UIColor sementara saya memiliki string.
Alix
11

Sayangnya, pernyataan peralihan hanya bisa digunakan pada tipe primitif. Anda memiliki beberapa opsi menggunakan koleksi.

Mungkin opsi terbaik adalah menyimpan setiap nilai sebagai entri dalam 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]];
ughoavgfhw
sumber
8

Agak terlambat tetapi bagi siapa pun di masa depan saya bisa membuat ini bekerja untuk saya

#define CASE(str) if ([__s__ isEqualToString:(str)])
#define SWITCH(s) for (NSString *__s__ = (s); ; )
#define DEFAULT
Newyork167
sumber
Ini menarik. Bisakah Anda menjelaskan lebih lanjut?
Chen Li Yong
6

Inilah cara yang lebih cerdas untuk menulis itu. Ini untuk menggunakan NSNumberFormatterdalam "mantra-out gaya" :

NSString *cardName = ...;

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

Perhatikan bahwa pemformat angka ingin string lebih kecil, jadi kita harus melakukannya sendiri sebelum meneruskannya ke pemformat.

Dave DeLong
sumber
5

Ada cara lain untuk melakukan itu, tetapi switchbukan salah satunya.

Jika Anda hanya memiliki beberapa string, seperti dalam contoh Anda, kode yang Anda miliki baik-baik saja. Jika Anda memiliki banyak case, Anda bisa menyimpan string sebagai kunci dalam kamus dan mencari nilai yang sesuai:

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

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

OLEH JAUH .. FAVORIT saya "Add-On" ObjC adalahObjectMatcher

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

DAN itu bekerja dengan non-string, TERLALU ... dalam loop, bahkan!

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.

Terbaik dari semua, ada beberapa {...}, :'s, dan ()' s

Alex Gray
sumber
3

Objective-c tidak berbeda dengan c dalam aspek ini, ia hanya dapat mengaktifkan apa yang dapat c (dan preproc def seperti NSInteger, NSUInteger, karena mereka pada akhirnya hanya diketikkan ke tipe integral).

Wikipedia:

c sintaks :

Pernyataan switch menyebabkan kontrol ditransfer ke salah satu dari beberapa pernyataan tergantung pada nilai ekspresi, yang harus memiliki tipe integral .

Jenis Integral :

Dalam ilmu komputer, integer adalah datum tipe data integral, tipe data yang mewakili beberapa subset terbatas dari integer matematika. Tipe data integral mungkin dari ukuran yang berbeda dan mungkin atau mungkin tidak diizinkan mengandung nilai negatif.

dikunyah
sumber
2

Saya agak terlambat ke pesta, tetapi untuk menjawab pertanyaan sebagaimana dinyatakan , ada cara yang lebih cerdas:

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

Catatan yang indexOfObjectakan mencari pertandingan menggunakan isEqual:, persis seperti dalam pertanyaan.

ilya n.
sumber
2

Membangun ide @Graham Perks yang diposting sebelumnya, merancang kelas sederhana untuk membuat pergantian string cukup sederhana dan bersih.

@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

Anda akan menggunakannya seperti ini:

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

Blok yang benar akan dieksekusi sesuai dengan string.

Inti dari solusi ini

Chuck Krutsinger
sumber
0

Saya tidak dapat mengomentari jawaban cris pada jawaban @ Chris tetapi saya ingin mengatakan bahwa:

Ada BATASAN untuk metode @ cris:

typedef enum tidak akan mengambil nilai alfanumerik

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

} CardType;

Jadi di sini adalah Satu lagi:

Tautan Stack over flow Buka jawaban pengguna ini "user1717750"

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

Nikmati Pengodean .....

Ek SAD.
sumber