2011-11-17 28 views
149

Có một cách thông minh hơn để viết lại điều này không?Có thể chuyển đổi mục tiêu-C trên NSString không?

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

Không, chuyển đổi chỉ hoạt động trên các loại int/bool/char/etc. – chown

+0

câu hỏi này hơi giống với câu hỏi này chỉ được đăng một giờ trước (http: // stackoverflow.com/questions/8161319/cao-performant-goal-c-lựa chọn thay thế-to-the-switch-tuyên bố-cho-đối tượng) –

+2

Có một số cách khác để làm điều đó. Ví dụ, tải một mảng với các giá trị và tìm kiếm một kết quả phù hợp trong mảng. Không có hiệu quả khủng khiếp, nhưng chúng làm giảm sự sao chép mã. –

Trả lời

134

Thật không may là chúng không thể. Đây là một trong những cách tốt nhất và được sử dụng nhiều nhất sau khi sử dụng các câu lệnh chuyển đổi, vì vậy hy vọng chúng sẽ nhảy vào bandwagon (hiện tại) Java (và những người khác)!

Nếu bạn đang làm tên thẻ, có thể chỉ định từng đối tượng thẻ một giá trị số nguyên và bật điều đó. Hoặc có lẽ là một enum, được coi là một số và do đó có thể được bật lên.

ví dụ:

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

} CardType; 

Xong cách này, Ace sẽ được tính bằng chữ 0, Hai như trường hợp 1, vv

+31

whaaaaaaaat ?? wow .. chỉ cần wow .. – abbood

+2

Đây là cách duy nhất nó nên được thực hiện. – Tristan

+4

@abbood Để biết thêm thông tin về enum, xem bài đăng [NS_ENUM & NS_OPTIONS] (http://www.nshipster.com/ns_enum-ns_options/) bởi Mattt Thompson. –

6

Có nhiều cách khác để làm điều đó, nhưng switch không phải là một trong số họ.

Nếu bạn chỉ có một vài chuỗi, như trong ví dụ của bạn, mã bạn có là tốt. Nếu bạn có nhiều trường hợp, bạn có thể lưu trữ các chuỗi dưới dạng các khóa trong từ điển và tra cứu giá trị tương ứng:

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

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

Thật không may, báo cáo chuyển đổi chỉ có thể được sử dụng trên các kiểu nguyên thủy. Tuy nhiên, bạn có một vài tùy chọn sử dụng các bộ sưu tập.

Có lẽ tùy chọn tốt nhất là lưu trữ từng giá trị dưới dạng mục nhập trong từ điển 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]]; 
3

Objective-c là không khác so với c trong khía cạnh này, nó chỉ có thể bật những gì c có thể (và preproc def của như NSInteger, NSUInteger, kể từ khi họ cuối cùng chỉ là typedef'd đến một loại không thể thiếu) .

Wikipedia:

c syntax:

Việc chuyển đổi nguyên nhân tuyên bố kiểm soát được chuyển giao cho một trong những báo cáo tùy thuộc vào giá trị của một biểu thức, mà phải có thể thiếu loại.

Integral Types:

Trong khoa học máy tính, một số nguyên là một dữ kiện của kiểu dữ liệu không thể thiếu, một loại dữ liệu đại diện cho một số tập con hữu hạn của số nguyên toán học. Các kiểu dữ liệu tích phân có thể có các kích thước khác nhau và có thể hoặc có thể không được phép chứa các giá trị âm.

6

Đây là cách thông minh hơn để viết điều đó. Đó là sử dụng một NSNumberFormatter trong "spell-out style":

NSString *cardName = ...; 

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

Lưu ý rằng định dạng số muốn chuỗi được lowercased, vì vậy chúng tôi phải làm điều đó bản thân mình trước khi đi qua nó vào định dạng.

112

Bạn có thể thiết lập một từ điển của khối, như thế này:

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 

Để có một phần 'mặc định', thay thế các dòng cuối cùng với:

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

Hy vọng rằng Apple sẽ dạy 'chuyển đổi 'một vài thủ thuật mới.

+29

Tôi không thể biết điều này thực sự khó chịu hay thực sự hay. Đã không bao giờ nghĩ đến việc này, cảm ơn. – endy

+2

Trong khi chúng tôi đang làm những thứ kỳ lạ như thế này, tại sao không làm cho lớp của riêng bạn mà kết thúc tốt đẹp một NSDictionary đầy đủ các phím NSString cho các đối tượng khối và sau đó cung cấp một khối cho các trường hợp mặc định? Bạn thậm chí có thể có nó hỗ trợ các ký hiệu chỉ số. – ArtOfWarfare

+1

@endy Tôi bỏ phiếu thực sự tuyệt vời. –

65

Đối với tôi, một cách dễ dàng thoải mái:

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

Tôi thích điều này. Nó trả lời các nhu cầu của hầu hết các tìm kiếm một câu trả lời cho vấn đề này, nó không mất nhiều hơn gõ hơn một chuyển đổi tương tự sẽ mất trong javascript, và nó là con người có thể đọc được. –

+4

Tôi sẽ không so sánh bản hack này với JS switch. Điều gì sẽ xảy ra nếu lập trình viên tiếp theo thêm một mục giữa item1 và item2? Quá nhiều tiềm năng cho việc giới thiệu lỗi – Aras

+0

là một hack tốt đẹp của nó, vì vậy tôi cung cấp cho bạn ngón tay cái lên cho các nỗ lực :) – Aras

0

Tôi không thể bình luận về câu trả lời cris về câu trả lời @Cris nhưng tôi muốn nói rằng:

Có một GIỚI HẠN cho của @ cris phương pháp:

typedef enum sẽ không có giá trị chữ và số

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

} CardType; 

Vì vậy, đây là một On e:

Link Stack over flow Đến người sử dụng trả lời "user1717750" này

3

THEO FAR .. my FAVORITE "ObjC Add-On" is 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 

VÀ nó hoạt động với không dây, TOO ... trong vòng, thậm chí!

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. 

tốt nhất của tất cả, có SO vài {...} 's, :' s, và () 's

1

tôi là loại muộn để đảng, nhưng để câu trả lời các câu hỏi như đã nêu , có một cách thông minh hơn:

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

Lưu ý rằng indexOfObject sẽ xem xét cho phù hợp với sử dụng isEqual:, chính xác như trong câu hỏi.

3

Một hơi muộn nhưng đối với bất cứ ai trong tương lai tôi đã có thể có được điều này để làm việc cho tôi

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

Điều này thật thú vị. Bạn có thể xây dựng thêm? –

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

Thưởng thức Mã hóa .....

+0

lol, đây là một thất bại lớn, nhưng tôi thích nỗ lực – Loxx

0

xây dựng trên ý tưởng @Graham Perks được đăng trước đó, được thiết kế một lớp đơn giản để làm cho việc chuyển đổi trên các chuỗi khá đơn giản và rõ ràng.

@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 

Bạn sẽ sử dụng nó như thế này:

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

Khối đúng sẽ thực hiện theo chuỗi.

Gist for this solution

Các vấn đề liên quan