Objective-C NSString'i açabilir mi?


166

Bunu yeniden yazmanın daha akıllı bir yolu var mı?

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
Hayır, switch yalnızca int / bool / char / etc türlerinde çalışır.
chown

Bu soru bir saat önce yayınlanan buna benzer. ( stackoverflow.com/questions/8161319/… )
Michael Dautermann

3
Bunu yapmanın birkaç alternatif yolu var. Örneğin, değerleri içeren bir dizi yükleyin ve dizide bir eşleşme arayın. Hiçbiri son derece verimli değildir, ancak kod çoğaltmasını azaltır.
Hot Licks

4
Bir yan not olarak, Apple'ın yeni dili (Swift) artık bir anahtar ifadesinde dizeleri karşılaştırmaya izin veriyor!
jaredsmith

4
Swift'e
geçin

Yanıtlar:


147

Ne yazık ki yapamazlar. Bu, switch ifadelerinin kullanımından sonra en iyi ve en çok arananlardan biridir, umarım (şimdi) Java (ve diğerleri) bant aralığına atlarlar!

Kart adları yapıyorsanız, belki de her kart nesnesine bir tamsayı değeri atayın ve açın. Ya da belki bir sayı olarak kabul edilen ve bu nedenle açılabilir bir numaralandırma.

Örneğin

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

} CardType;

Bu şekilde yapılırsa Ace, 0. durum, 1. durum olarak iki vb.


4
@abbood Enum hakkında daha fazla bilgi için Mattt Thompson tarafından yayınlanan NS_ENUM & NS_OPTIONS yayınına bakın .
Basil Bourque

@abbood Yorumunuz ne anlama geliyor? Kulağa kötü geliyor ama bana iyi geliyor. Açıklayabilir misiniz?
Alan Andrade

Anladığım kadarıyla, CardTypekapalı olanlara eşit olamaz @""örneğin:[CardType isEqualToString:@"Three"]
Adromil Balais

120

Bunun gibi bir blok sözlüğü ayarlayabilirsiniz:

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

'Varsayılan' bir bölüme sahip olmak için, son satırı aşağıdaki ile değiştirin:

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

Umarım Apple birkaç yeni numarayı 'değiştirmeyi' öğretir.


35
Bunun gerçekten kötü mü yoksa gerçekten havalı mı olduğunu söyleyemem. Bunu yapmayı hiç düşünmezdim, teşekkürler.
son

2
Biz böyle garip şeyler yaparken, neden blok nesneler için NSString anahtarları ile dolu bir NSDictionary sarar ve sonra varsayılan durumlar için başka bir blok sağlar kendi sınıf yapmak? Abonelik gösterimini desteklemesini bile sağlayabilirsiniz.
ArtOfWarfare

1
Sadece bunun için bir NSDictionary alt sınıfı yaparsanız ekstra puan: P
CommaToast

2
Başlık altında, C # büyük anahtar ifadeleri için bunu yapar.
Hank Schultz

78

Benim için güzel ve kolay bir yol:

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
Bunu severim. Bu sorunun cevabını arayanların çoğunun ihtiyaçlarını karşılar, benzer bir anahtarın javascript'te alacağından çok daha fazla yazmayı gerektirmez ve insan tarafından okunabilir.
ew parris

4
Ben JS anahtarı ile bu kesmek karşılaştırmak olmaz. Bir sonraki programcı item1 ve item2 arasına bir öğe eklerse ne olur? Böcek getirme potansiyeli çok fazla
Aras

Bu olsa güzel bir kesmek, bu yüzden çaba için başparmak vazgeçmek :)
Aras

@Aras Bir sonraki programcının yeni bir giriş eklemesi gerekiyorsa, bunu işlemek için sonunda yeni bir vaka ifadesiyle dizinin sonuna eklerler. Dizide @ "item3" den sonra @ "item0" eklenebilir, ardından işlemek için bir vaka 3: eklenebilir.
sbonkosky

1
Yolunu tamamen beğendim. Çok temiz. Ben kategori yazıyorum ve benimle dize varken UIColor dönmek gerekir.
Alix

11

Maalesef, switch deyimleri yalnızca ilkel türlerde kullanılabilir. Yine de koleksiyonları kullanarak birkaç seçeneğiniz var.

Muhtemelen en iyi seçenek, her değeri bir NSDictionary içine giriş olarak saklamak olacaktır.

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

Biraz geç ama gelecekteki herkes için bunu benim için çalıştırabildim

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

Bu ilginç. Daha fazla ayrıntı verebilir misiniz?
Chen Li Yong

6

İşte bunu yazmanın daha akıllı yolu. Bir kullanmak var NSNumberFormatteriçinde "yazım tarzı dışında" :

NSString *cardName = ...;

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

Sayı biçimlendiricisinin dizenin küçük harfle yazılmasını istediğini unutmayın, bu yüzden biçimlendiriciye aktarmadan önce bunu kendimiz yapmak zorundayız.


5

Bunu yapmanın başka yolları da var, ama switchonlardan biri değil.

Örneğinizde olduğu gibi yalnızca birkaç dizeniz varsa, sahip olduğunuz kod iyidir. Çok sayıda vakanız varsa, dizeleri sözlükte anahtar olarak saklayabilir ve karşılık gelen değeri arayabilirsiniz:

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

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

4

UZAKTA .. benim FAVORİ "ObjC Eklentisi"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

VE hatta string olmayan, TOO ... döngüler halinde bile çalışıyor!

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.

En iyisi, çok az {...}', :' ve ()'var


3

Objective-c bu açıdan c'den farklı değildir, sadece c'nin ne yapabileceğini açabilir (ve sonuç olarak sadece integral bir tipte tip tanımlandıkları için preproc def NSNSteger, NSUInteger gibi).

Wikipedia:

c sözdizimi :

Switch deyimi, denetimin , integral türünde olması gereken bir ifadenin değerine bağlı olarak birkaç deyimden birine aktarılmasına neden olur .

İntegral Çeşitleri :

Bilgisayar biliminde, bir tamsayı, matematiksel tamsayıların bazı sonlu alt kümelerini temsil eden bir veri türü olan integral veri türünün bir verisidir. İntegral veri tipleri farklı boyutlarda olabilir ve negatif değerler içermesine izin verilebilir veya verilmeyebilir.


2

Partiye geç kaldım, ancak soruyu belirtildiği gibi cevaplamak için daha akıllı bir yol var:

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

Eşleşmeyi tam olarak soruda olduğu gibi indexOfObjectarayacağına dikkat edin isEqual:.


2

Daha önce yayınlanan @Graham Perks fikri üzerine inşa etmek, dizeleri açmayı oldukça basit ve temiz hale getirmek için basit bir sınıf tasarladı.

@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

Bunu şöyle kullanırsınız:

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

Doğru blok dizeye göre yürütülür.

Bu çözümün özü


0

@Cris cevabına cris'ın cevabı hakkında yorum yapamam ama şunu söylemek isterim:

@ Cris yöntemi için bir LIMITATION var:

typedef enum alfasayısal değerler almayacak

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

} CardType;

İşte bir tane daha:

Link Stack over flow Bu kullanıcı yanıtına git "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;
    }
}

Kodlamanın keyfini çıkarın .....

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.