2008-09-19 21 views
14

Tôi đang thực hiện một số chương trình Mục tiêu-C có liên quan đến phân tích cú pháp một NSXmlDocument và điền vào một thuộc tính đối tượng từ kết quả.Chuyển đổi mục tiêu-C bằng cách sử dụng các đối tượng?

Phiên bản đầu tiên trông như thế này:

if([elementName compare:@"companyName"] == 0) 
    [character setCorporationName:currentElementText]; 
else if([elementName compare:@"corporationID"] == 0) 
    [character setCorporationID:currentElementText]; 
else if([elementName compare:@"name"] == 0) 
    ... 

Nhưng tôi không thích những mẫu if-else-if-else này sản xuất. Nhìn vào tuyên bố switch Tôi thấy rằng tôi chỉ có thể xử lý ints, chars vv và không phải đối tượng ... vì vậy có một mô hình triển khai tốt hơn mà tôi không biết?

BTW tôi đã thực sự tìm ra một giải pháp tốt hơn để thiết lập thuộc tính của đối tượng, nhưng tôi muốn biết cụ thể về if - mẫu else vs switch trong Objective-C

+0

Điều này không giúp gì cả, nhưng trong VB.Net, bạn có thể sử dụng lệnh chuyển (chọn trong vb) trên bất kỳ loại giá trị nào và trình biên dịch sẽ thực hiện chuyển đổi sang dạng if-elseif-else khi biên dịch , nếu không thể thực hiện được bằng nhảy trực tiếp. Cá nhân, tôi nghĩ rằng tất cả các ngôn ngữ nên có tính năng này. – Kibbee

+0

Câu trả lời liên quan: http://stackoverflow.com/questions/8161737/can-objective-c-switch-on-nsstring/10177956#10177956 –

Trả lời

12

Tôi hy vọng tất cả các bạn sẽ tha thứ cho tôi đi ra ngoài cánh một ở đây, nhưng tôi muốn giải quyết các câu hỏi tổng quát hơn của phân tích tài liệu XML trong Cocoa mà không cần các câu lệnh if-else. Câu hỏi như ban đầu được chỉ định gán văn bản phần tử hiện tại cho một biến cá thể của đối tượng ký tự. Như jmah đã chỉ ra, điều này có thể được giải quyết bằng cách sử dụng mã hóa khóa-giá trị. Tuy nhiên, trong một tài liệu XML phức tạp hơn, điều này có thể không thực hiện được. Hãy xem xét ví dụ như sau.

<xmlroot> 
    <corporationID> 
     <stockSymbol>EXAM</stockSymbol> 
     <uuid>31337</uuid> 
    </corporationID> 
    <companyName>Example Inc.</companyName> 
</xmlroot> 

Có nhiều cách để giải quyết vấn đề này. Tắt đầu của tôi, tôi có thể nghĩ đến hai sử dụng NSXMLDocument. Việc đầu tiên sử dụng NSXMLElement. Nó khá đơn giản và không liên quan đến vấn đề if-else. Bạn chỉ cần lấy phần tử gốc và đi qua từng phần tử có tên của nó.

NSXMLElement* root = [xmlDocument rootElement]; 

// Assuming that we only have one of each element. 
[character setCorperationName:[[[root elementsForName:@"companyName"] objectAtIndex:0] stringValue]]; 

NSXMLElement* corperationId = [root elementsForName:@"corporationID"]; 
[character setCorperationStockSymbol:[[[corperationId elementsForName:@"stockSymbol"] objectAtIndex:0] stringValue]]; 
[character setCorperationUUID:[[[corperationId elementsForName:@"uuid"] objectAtIndex:0] stringValue]]; 

Tiếp theo sử dụng NSXMLNode tổng quát hơn, đi qua cây và trực tiếp sử dụng cấu trúc if-else.

// The first line is the same as the last example, because NSXMLElement inherits from NSXMLNode 
NSXMLNode* aNode = [xmlDocument rootElement]; 
while(aNode = [aNode nextNode]){ 
    if([[aNode name] isEqualToString:@"companyName"]){ 
     [character setCorperationName:[aNode stringValue]]; 
    }else if([[aNode name] isEqualToString:@"corporationID"]){ 
     NSXMLNode* correctParent = aNode; 
     while((aNode = [aNode nextNode]) == nil && [aNode parent != correctParent){ 
      if([[aNode name] isEqualToString:@"stockSymbol"]){ 
       [character setCorperationStockSymbol:[aNode stringValue]]; 
      }else if([[aNode name] isEqualToString:@"uuid"]){ 
       [character setCorperationUUID:[aNode stringValue]]; 
      } 
     } 
    } 
} 

Đây là một ứng cử viên tốt để loại bỏ cấu trúc if-else, nhưng giống như vấn đề ban đầu, chúng tôi không thể đơn giản sử dụng chuyển đổi trường hợp ở đây. Tuy nhiên, chúng ta vẫn có thể loại bỏ if-else bằng cách sử dụng performSelector. Bước đầu tiên là xác định phương thức cho mỗi phần tử.

- (NSNode*)parse_companyName:(NSNode*)aNode 
{ 
    [character setCorperationName:[aNode stringValue]]; 
    return aNode; 
} 

- (NSNode*)parse_corporationID:(NSNode*)aNode 
{ 
    NSXMLNode* correctParent = aNode; 
    while((aNode = [aNode nextNode]) == nil && [aNode parent != correctParent){ 
     [self invokeMethodForNode:aNode prefix:@"parse_corporationID_"]; 
    } 
    return [aNode previousNode]; 
} 

- (NSNode*)parse_corporationID_stockSymbol:(NSNode*)aNode 
{ 
    [character setCorperationStockSymbol:[aNode stringValue]]; 
    return aNode; 
} 

- (NSNode*)parse_corporationID_uuid:(NSNode*)aNode 
{ 
    [character setCorperationUUID:[aNode stringValue]]; 
    return aNode; 
} 

Phép thuật xảy ra trong phương thức invokeMethodForNode: prefix:. Chúng tôi tạo bộ chọn dựa trên tên của phần tử và thực hiện bộ chọn đó bằng aNode làm tham số duy nhất. Ví dụ, chúng tôi đã loại bỏ sự cần thiết cho một tuyên bố nếu khác. Đây là mã cho phương thức đó.

- (NSNode*)invokeMethodForNode:(NSNode*)aNode prefix:(NSString*)aPrefix 
{ 
    NSNode* ret = nil; 
    NSString* methodName = [NSString stringWithFormat:@"%@%@:", prefix, [aNode name]]; 
    SEL selector = NSSelectorFromString(methodName); 
    if([self respondsToSelector:selector]) 
     ret = [self performSelector:selector withObject:aNode]; 
    return ret; 
} 

Bây giờ, thay vì lớn hơn if-else của chúng tôi (một trong đó phân biệt giữa CompanyName và corporationID), chúng ta có thể chỉ cần viết một dòng mã

NSXMLNode* aNode = [xmlDocument rootElement]; 
while(aNode = [aNode nextNode]){ 
    aNode = [self invokeMethodForNode:aNode prefix:@"parse_"]; 
} 

Bây giờ tôi xin lỗi nếu tôi có bất kỳ của điều này sai, nó đã được một thời gian kể từ khi tôi đã viết bất cứ điều gì với NSXMLDocument, nó vào cuối đêm và tôi đã không thực sự kiểm tra mã này. Vì vậy, nếu bạn thấy bất cứ điều gì sai, xin vui lòng để lại một bình luận hoặc chỉnh sửa câu trả lời này.

Tuy nhiên, tôi tin rằng tôi đã chỉ cho thấy cách chọn đúng tên có thể được sử dụng trong Cocoa để loại bỏ hoàn toàn các câu lệnh if-else trong trường hợp như thế này. Có một vài trường hợp mắc kẹt và góc. PerformSelector: họ của các phương thức chỉ nhận 0, 1, hoặc 2 phương thức đối số mà các đối số và kiểu trả về là các đối tượng, vì vậy nếu các kiểu đối số và kiểu trả về không phải là các đối tượng, hoặc nếu có nhiều hơn hai đối số, thì bạn sẽ phải sử dụng NSInvocation để gọi nó. Bạn phải đảm bảo rằng các tên phương thức bạn tạo sẽ không gọi các phương thức khác, đặc biệt nếu đích của cuộc gọi là một đối tượng khác, và lược đồ đặt tên phương thức cụ thể này sẽ không hoạt động trên các phần tử có ký tự không phải chữ số. Bạn có thể vượt qua điều đó bằng cách thoát khỏi các tên phần tử XML trong tên phương thức của bạn bằng cách nào đó, hoặc bằng cách xây dựng một NSDictionary bằng cách sử dụng các tên phương thức như các khóa và các bộ chọn làm các giá trị. Điều này có thể nhận được khá nhiều bộ nhớ và sẽ mất nhiều thời gian hơn. performSelector công văn như tôi mô tả là khá nhanh. Đối với các câu lệnh if-else rất lớn, phương thức này thậm chí có thể nhanh hơn câu lệnh if-else.

+0

Tôi thích sự nhỏ gọn của giải pháp này. Chỉ cần một vài nhận xét: đó là NSXMLNode không phải NSNode. NSXMLNode * ret - Tôi không thể nghĩ ra bất kỳ việc sử dụng nào vì aNode đã được thiết lập bởi nextNode. Sử dụng performSelector như thế này sẽ đưa ra cảnh báo: "performSelector có thể gây rò rỉ vì bộ chọn của nó không xác định". Cách ngắn nhất xung quanh việc này là sử dụng objc_msgGửi nhưng sau đó bạn phải tắt 'Bật kiểm tra nghiêm ngặt lệnh objc_msgGửi cuộc gọi'. Thực hiện việc này trong [self respondsToSelector: selector] để giảm bớt một số thiếu sót objc_msgSend. –

+0

Xin cảm ơn vì đã bình luận. Câu trả lời này là một wiki cộng đồng, vì vậy vui lòng chỉnh sửa bất kỳ lỗi nào bạn có thể tìm thấy. Tuy nhiên, tôi muốn chỉ ra rằng câu trả lời này là tập thể dục nhiều hơn trong việc khám phá việc thực hiện với một giới hạn tùy ý, và không có ý định là lời khuyên về cách viết mã sản xuất. –

2

Các refactoring phổ biến nhất gợi ý để loại bỏ nếu -báo cáo chuyển đổi hoặc chuyển đổi đang giới thiệu tính đa hình (xem http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html). Loại bỏ các điều kiện như vậy là quan trọng nhất khi chúng được nhân đôi. Trong trường hợp phân tích cú pháp XML như mẫu của bạn, bạn chủ yếu di chuyển dữ liệu đến một cấu trúc tự nhiên hơn để bạn không phải sao chép điều kiện ở nơi khác. Trong trường hợp này câu lệnh if-else hoặc switch có lẽ là đủ tốt.

3

Triển khai thực hiện if-else bạn có đúng cách để thực hiện việc này, vì switch sẽ không hoạt động với các đối tượng. Ngoài việc có thể là một chút khó khăn hơn để đọc (đó là chủ quan), không có nhược điểm thực sự trong việc sử dụng if-else báo cáo theo cách này.

1

Trong trường hợp này, tôi không chắc liệu bạn có thể dễ dàng cấu trúc lại lớp để giới thiệu tính đa hình như Bradley gợi ý hay không, vì đây là lớp bản địa của Cocoa. Thay vào đó, Objective-C cách để làm điều đó là sử dụng một loại lớp để thêm một phương pháp elementNameCode để NSSting:

typedef enum { 
     companyName = 0, 
     companyID, 
     ..., 
     Unknown 
    } ElementCode; 

    @interface NSString (ElementNameCodeAdditions) 
    - (ElementCode)elementNameCode; 
    @end 

    @implementation NSString (ElementNameCodeAdditions) 
    - (ElementCode)elementNameCode { 
     if([self compare:@"companyName"]==0) { 
      return companyName; 
     } else if([self compare:@"companyID"]==0) { 
      return companyID; 
     } ... { 

     } 

     return Unknown; 
    } 
    @end 

Trong code của bạn, bây giờ bạn có thể sử dụng một công tắc trên [elementName elementNameCode] (và đạt được những lời cảnh báo trình biên dịch liên quan nếu bạn quên kiểm tra một trong những thành viên enum, vv).

Khi Bradley chỉ ra, điều này có thể không đáng giá nếu logic chỉ được sử dụng ở một nơi.

3

Mặc dù không nhất thiết phải là cách tốt hơn để làm điều gì đó như vậy trong một lần sử dụng, tại sao lại sử dụng "so sánh" khi bạn có thể sử dụng "isEqualToString"? Điều đó dường như có hiệu suất cao hơn so với việc so sánh sẽ dừng lại ở ký tự không khớp đầu tiên, thay vì trải qua toàn bộ điều để tính kết quả so sánh hợp lệ (mặc dù nghĩ đến nó so sánh có thể rõ ràng tại cùng một điểm) - mặc dù nó sẽ trông sạch hơn một chút vì cuộc gọi đó trả về một BOOL.

if([elementName isEqualToString:@"companyName"]) 
    [character setCorporationName:currentElementText]; 
else if([elementName isEqualToString:@"corporationID"]) 
    [character setCorporationID:currentElementText]; 
else if([elementName isEqualToString:@"name"]) 
+0

Như được truy vấn trong câu hỏi ban đầu, tôi đã tìm thấy cách tốt hơn để thực hiện cài đặt thuộc tính . Tôi chỉ đang tìm kiếm lời khuyên về bất kỳ mô hình nào tốt hơn để xử lý mô hình if-else. – craigb

+0

Rất tốt. Nó vẫn là thông tin hữu ích cho những người thích những cách sạch hơn để so sánh chuỗi. Bạn đang lợi dụng downvotes, an ủi duy nhất là nó chi phí cho bạn danh tiếng để loại bỏ thông tin hoàn toàn tốt. Tôi sẽ không phạm sai lầm khi giúp bạn lần nữa. –

13

Bạn nên tận dụng lợi thế của Key-Value Coding:

[character setValue:currentElementText forKey:elementName]; 

Nếu dữ liệu là không tin cậy, bạn có thể muốn xem xét rằng việc quan trọng là hợp lệ:

if (![validKeysCollection containsObject:elementName]) 
    // Exception or error 
+0

Như đã nêu trong câu hỏi, tôi đã tìm thấy một cách tốt hơn để thiết lập các thuộc tính này và chỉ tìm kiếm lời khuyên về mẫu if-else mà tôi không thích. – craigb

+0

Nhưng đó là điểm, để tránh tự mình thực hiện nhiều công việc và cho phép các khía cạnh của ngôn ngữ (hoặc khung công tác) xử lý nó.Mẫu if-else-else-else hoặc switch trên giá trị đối tượng sẽ không được khuyến khích, khi bạn có thể thực hiện những việc như tra cứu từ điển. – jmah

4

Một cách Tôi đã làm điều này với NSStrings là bằng cách sử dụng một NSDictionary và enums. Nó có thể không phải là thanh lịch nhất, nhưng tôi nghĩ nó làm cho mã dễ đọc hơn một chút.Giả sau đây được chiết xuất từ ​​one of my projects:

typedef enum { UNKNOWNRESIDUE, DEOXYADENINE, DEOXYCYTOSINE, DEOXYGUANINE, DEOXYTHYMINE } SLSResidueType; 

static NSDictionary *pdbResidueLookupTable; 
... 

if (pdbResidueLookupTable == nil) 
{ 
    pdbResidueLookupTable = [[NSDictionary alloc] initWithObjectsAndKeys: 
          [NSNumber numberWithInteger:DEOXYADENINE], @"DA", 
          [NSNumber numberWithInteger:DEOXYCYTOSINE], @"DC", 
          [NSNumber numberWithInteger:DEOXYGUANINE], @"DG", 
          [NSNumber numberWithInteger:DEOXYTHYMINE], @"DT", 
          nil]; 
} 

SLSResidueType residueIdentifier = [[pdbResidueLookupTable objectForKey:residueType] intValue]; 
switch (residueIdentifier) 
{ 
    case DEOXYADENINE: do something; break; 
    case DEOXYCYTOSINE: do something; break; 
    case DEOXYGUANINE: do something; break; 
    case DEOXYTHYMINE: do something; break; 
} 
7

Tôi có đề xuất sử dụng macro không?

#define TEST(_name, _method) \ 
    if ([elementName isEqualToString:@ _name]) \ 
    [character _method:currentElementText]; else 
#define ENDTEST { /* empty */ } 

TEST("companyName",  setCorporationName) 
TEST("setCorporationID", setCorporationID ) 
TEST("name",    setName   ) 
: 
: 
ENDTEST 
+0

Đẹp, không nghĩ về điều đó. Không được sử dụng để sử dụng macro nhiều. – craigb

7

Nếu bạn muốn sử dụng càng ít mã càng tốt, và tên phần tử và setters của bạn đều được đặt tên như vậy là nếu elementName là @ "foo", sau đó setter là setFoo :, bạn có thể làm một cái gì đó như:

SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", [elementName capitalizedString]]); 

[character performSelector:selector withObject:currentElementText]; 

hoặc thậm chí có thể:

[character setValue:currentElementText forKey:elementName]; // KVC-style 

mặc dù những ý dĩ nhiên là một chút chậm hơn so với sử dụng một loạt các câu lệnh if.

[Chỉnh sửa: Tùy chọn thứ hai đã được đề cập bởi một người nào đó; 2!!]

+0

+1 cho nó khá gọn gàng như ObjC có thể là ... – epatel

+0

Tôi đã thêm một sửa đổi cho điều này bên dưới - http://stackoverflow.com/questions/104339/objective-c-switch-using-objects/1215783#1215783 –

3

Có một cách khá đơn giản để giải quyết các câu lệnh if-else trong một ngôn ngữ như Objective-C. Có, bạn có thể sử dụng lớp con và ghi đè, tạo một nhóm các lớp con thực hiện cùng một phương thức khác nhau, gọi cách triển khai đúng lúc chạy bằng cách sử dụng một thông báo chung. Điều này hoạt động tốt nếu bạn muốn chọn một trong vài triển khai, nhưng nó có thể dẫn đến sự gia tăng không cần thiết của các lớp con nếu bạn có nhiều triển khai nhỏ, hơi khác nhau như bạn có xu hướng có các câu lệnh if-else hoặc switch dài hơn.

Thay vào đó, hãy xác định phần thân của mỗi mệnh đề if/else-if thành phương thức riêng của nó, tất cả trong cùng một lớp. Đặt tên cho các tin nhắn gọi chúng theo kiểu tương tự. Bây giờ tạo một NSArray chứa các bộ chọn của các thông điệp đó (thu được bằng cách sử dụng @selector()). Coerce chuỗi bạn đã thử nghiệm trong các điều kiện vào một bộ chọn bằng NSSelectorFromString() (bạn có thể cần phải nối thêm các từ hoặc dấu hai chấm cho nó đầu tiên tùy thuộc vào cách bạn đặt tên cho các thông điệp đó và có tham số hay không). Bây giờ có tự thực hiện chọn bằng cách sử dụng performSelector :.

Cách tiếp cận này có nhược điểm là nó có thể làm lộn xộn lớp học với nhiều thư mới, nhưng có lẽ tốt hơn là làm lộn xộn một lớp đơn lẻ hơn toàn bộ phân cấp lớp với lớp con mới.

1

Những gì chúng tôi đã thực hiện trong các dự án của chúng tôi, nơi chúng tôi cần phải sắp xếp điều này nhiều lần, là thiết lập ánh xạ CFDictionary tĩnh các chuỗi/đối tượng để kiểm tra với giá trị số nguyên đơn giản. Nó dẫn đến mã trông giống như sau:

static CFDictionaryRef map = NULL; 
int count = 3; 
const void *keys[count] = { @"key1", @"key2", @"key3" }; 
const void *values[count] = { (uintptr_t)1, (uintptr_t)2, (uintptr_t)3 }; 

if (map == NULL) 
    map = CFDictionaryCreate(NULL,keys,values,count,&kCFTypeDictionaryKeyCallBacks,NULL); 


switch((uintptr_t)CFDictionaryGetValue(map,[node name])) 
{ 
    case 1: 
     // do something 
     break; 
    case 2: 
     // do something else 
     break; 
    case 3: 
     // this other thing too 
     break; 
} 

Nếu bạn đang nhắm mục tiêu chỉ Leopard, bạn có thể sử dụng NSMapTable thay vì CFDictionary.

3

viết bài này như một phản ứng với câu trả lời của Wevah trên - Tôi sẽ đã chỉnh sửa, nhưng tôi không có đủ uy tín cao nào:

tiếc là phá vỡ phương pháp đầu tiên cho các lĩnh vực với nhiều hơn một từ trong họ - như xPosition. capitalizedString sẽ chuyển đổi thành Xposition, khi kết hợp với định dạng cho bạn setXposition:. Chắc chắn không phải những gì được mong muốn ở đây. Đây là những gì tôi đang sử dụng trong mã của tôi:

NSString *capName = [elementName stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:[[elementName substringToIndex:1] uppercaseString]]; 
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"set%@:", capName]); 

Không đẹp bằng phương pháp đầu tiên, nhưng nó hoạt động.

+0

Cảm ơn vì đã bắt! – Wevah

3

Tôi đã đưa ra giải pháp sử dụng các khối để tạo cấu trúc giống như chuyển đổi cho các đối tượng. Có nó đi:

BOOL switch_object(id aObject, ...) 
{ 
    va_list args; 
    va_start(args, aObject); 

    id value = nil; 
    BOOL matchFound = NO; 

    while ((value = va_arg(args,id))) 
    { 
     void (^block)(void) = va_arg(args,id); 
     if ([aObject isEqual:value]) 
     { 
      block(); 
      matchFound = YES; 
      break; 
     } 
    } 

    va_end(args); 
    return matchFound; 
} 

Như bạn có thể thấy, đây là hàm oldschool C với danh sách đối số biến. Tôi vượt qua đối tượng để được kiểm tra trong đối số đầu tiên, tiếp theo là cặp case_value-case_block.(Nhớ lại rằng khối Objective-C chỉ là các đối tượng.) Vòng lặp while tiếp tục trích xuất các cặp này cho đến khi giá trị đối tượng được khớp hoặc không còn trường hợp nào (xem ghi chú bên dưới).

Cách sử dụng:

NSString* str = @"stuff"; 
switch_object(str, 
       @"blah", ^{ 
        NSLog(@"blah"); 
       }, 
       @"foobar", ^{ 
        NSLog(@"foobar"); 
       }, 
       @"stuff", ^{ 
        NSLog(@"stuff"); 
       }, 
       @"poing", ^{ 
        NSLog(@"poing"); 
       }, 
       nil); // <-- sentinel 

// will print "stuff" 

Ghi chú:

  • đây là một xấp xỉ đầu tiên mà không cần bất kỳ kiểm tra lỗi
  • thực tế là xử lý trường hợp là các khối, đòi hỏi phải thận trọng hơn khi nói đến tầm nhìn , quản lý phạm vi và bộ nhớ của các biến được tham chiếu từ trong phạm vi
  • nếu bạn quên bưu điện, bạn sẽ phải chịu số phận: P
  • bạn có thể sử dụng giá trị trả về boolean để kích hoạt một "mặc định" trường hợp khi không ai trong số các trường hợp đã được xuất hiện
+0

thú vị, tôi thích nó :-) – craigb

+0

Tôi đã đặt trường hợp khối khai thác trước khi kiểm tra 'isEqual:', nếu không đối tượng được kiểm tra không cần thiết cho sự bình đẳng với đối tượng khối. – Lvsti

+0

@Lvsti, +1 Tôi thích phương pháp chặn này. Tôi tò mò, những gì bạn nghĩ về phương pháp tiếp cận chuỗi bộ lọc dựa trên khối của tôi, tôi chỉ đăng là câu trả lời. – vikingosegundo

0

Tương tự như Lvsti Tôi đang sử dụng khối để thực hiện một mô hình chuyển đổi trên các đối tượng.

Tôi đã viết một chuỗi dựa trên khối lọc rất đơn giản, có khối n bộ lọc và thực hiện từng bộ lọc trên đối tượng.
Mỗi bộ lọc có thể thay đổi đối tượng, nhưng phải trả lại. Không có vấn đề gì.

NSObject + Functional.h

#import <Foundation/Foundation.h> 
typedef id(^FilterBlock)(id element, NSUInteger idx, BOOL *stop); 

@interface NSObject (Functional) 
-(id)processByPerformingFilterBlocks:(NSArray *)filterBlocks; 
@end 

NSObject + Functional.m

@implementation NSObject (Functional) 
-(id)processByPerformingFilterBlocks:(NSArray *)filterBlocks 
{ 
    __block id blockSelf = self; 
    [filterBlocks enumerateObjectsUsingBlock:^(id (^block)(id,NSUInteger idx, BOOL*) , NSUInteger idx, BOOL *stop) { 
     blockSelf = block(blockSelf, idx, stop); 
    }]; 

    return blockSelf; 
} 
@end 

Bây giờ chúng ta có thể thiết lập n FilterBlocks để kiểm tra các trường hợp khác nhau.

FilterBlock caseYES = ^id(id element, NSUInteger idx, BOOL *breakAfter){ 
    if ([element isEqualToString:@"YES"]) { 
     NSLog(@"You did it"); 
     *breakAfter = YES; 
    } 
    return element; 
}; 

FilterBlock caseNO = ^id(id element, NSUInteger idx, BOOL *breakAfter){ 
    if ([element isEqualToString:@"NO"]) { 
     NSLog(@"Nope"); 
     *breakAfter = YES; 
    } 
    return element; 
}; 

Bây giờ chúng ta dính vào những khối chúng tôi muốn kiểm tra như một chuỗi bộ lọc trong một mảng:

NSArray *filters = @[caseYES, caseNO]; 

và có thể thực hiện nó trên một đối tượng

id obj1 = @"YES"; 
id obj2 = @"NO"; 
[obj1 processByPerformingFilterBlocks:filters]; 
[obj2 processByPerformingFilterBlocks:filters]; 

Cách tiếp cận này có thể được sử dụng để chuyển đổi mà còn cho bất kỳ ứng dụng chuỗi bộ lọc (điều kiện) nào, vì các khối có thể chỉnh sửa phần tử và truyền nó lên.

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