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 / etc类型。
chown

这个问题有点类似这个贴只有一个小时前(stackoverflow.com/questions/8161319/...
迈克尔Dautermann

3
有几种替代方法可以做到这一点。例如,使用值加载数组并在数组中搜索匹配项。没有一个非常高效,但是它们确实减少了代码重复。
热门

4
作为附带说明,Apple的新语言(Swift)现在允许在switch语句中比较字符串!
jaredsmith 2014年

4
切换到Swift;)
前往主题themario

Answers:


147

不幸的是他们不能。这是使用switch语句的最佳方式和最受欢迎的方法之一,因此希望他们跳上(现在)Java(和其他)潮流!

如果要输入卡名称,则可以为每个卡对象分配一个整数值,然后将其打开。或者一个枚举,它被认为是一个数字,因此可以被打开。

例如

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

} CardType;

这样,Ace等于情况0,两个等于情况1,依此类推。


4
@abbood有关枚举的更多信息,请参见Mattt Thompson 发表的NS_ENUM和NS_OPTIONS
罗勒·布尔克

@abbood您的评论应该是什么意思?听起来这是一个错误的答案,但对我来说似乎还可以。你能解释一下吗?
艾伦·安德拉德

据我了解,CardType不能等于任何封闭的内容,@""例如:[CardType isEqualToString:@"Three"]
Adromil Balais

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

希望苹果会教给“切换”一些新技巧。


35
我不知道这是真的很讨厌还是很酷。永远不会想到这样做,谢谢。
2013年

2
虽然我们正在做类似这样的事情,但为什么不创建自己的类,该类将NSDictionary包裹了完整的NSString键用于块对象,然后为默认情况提供了另一个块?您甚至可以支持下标表示法。
ArtOfWarfare 2013年

1
如果您为此
专门

2
在幕后,这是C#处理大型switch语句的方式。
汉克·舒尔茨

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 2014年

4
我不会将此hack与JS switch进行比较。如果下一个程序员在item1和item2之间添加一个项目会怎样?引入的bug太多的潜力
阿拉斯

它是一个不错的技巧,所以我为您的努力表示赞许:)
Aras 2014年

@Aras如果下一个程序员需要添加一个新条目,那么他们会将其添加到数组的末尾,并在末尾使用新的case语句来处理它。因此可以在数组中的@“ item3”之后添加@“ item0”,然后添加一种情况3:来处理它。
sbonkosky 2014年

1
我完全喜欢你的方式。非常整洁。我正在编写类别,并且在我有字符串时需要返回UIColor。
Alix 2014年

11

不幸的是,switch语句只能在基本类型上使用。但是,使用集合确实有一些选择。

最好的选择可能是将每个值作为条目存储在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 Add-On”是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

而且它可以与非字符串一起使用,也可以循环使用!

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和()


3

在这方面,Objective-c与c并无不同,它只能打开c可以进行的操作(和preproc def就像NSInteger,NSUInteger,因为它们最终只是被类型定义为整数类型)。

维基百科:

c语法

switch语句根据表达式的值将控制权转移到多个语句之一,该值必须具有整数type

整体类型

在计算机科学中,整数是整数数据类型的数据,该数据类型表示数学整数的某些有限子集。整数数据类型可能具有不同的大小,并且可能允许也可能不允许包含负值。


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答案,但我想说的是:

@cris的方法有一个局限性:

typedef枚举将不使用字母数字值

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

享受编码.....

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.