2012-11-22 39 views
7

Điều này khác với các bài viết khác "Tôi có thể kiểm tra loại khối" trên SO, theo như tôi có thể nói.Loại mục tiêu-C kiểm tra một khối?

Tôi muốn biết nếu được đưa ra một đối tượng khối chữ ký không xác định, tôi có thể tìm hiểu đối số nào nó chấp nhận trước khi gọi?

Tôi có một tình huống mà tôi có một số cuộc gọi lại được liên kết với các đối tượng trong từ điển. Tôi muốn một số trong những callbacks đó mong đợi một bộ đối số khác. Ví dụ ở đây là cực kỳ đơn giản, nhưng tôi nghĩ rằng nó được điểm trên.

Tôi làm cách nào để tìm hiểu xem một khối thuộc loại mà tôi đã nhập trước đó?

//MyClass.m 

// I start by declare two block types 
typedef void (^callbackWithOneParam)(NSString*); 
typedef void (^callbackWithTwoParams)(NSString*, NSObject*); 

........ 

// I create a dictionary mapping objects to callback blocks 

self.dict = @{ 
    @"name": "Foo", 
    @"callback": ^(NSString *aString) { 
    // do stuff with string 
    } 
}, { 
    @"name": "Bar", 
    @"callback": ^(NSString *aString, NSObject *anObject) { 
    // do stuff with string AND object 
    } 
} 

..... 

// Later, this method is called. 
// It looks up the "name" parameter in our dictionary, 
// and invokes the associated callback accordingly. 

-(void) invokeCallbackForName:(NSString*)name { 
    // What is the type of the result of this expression? 
    [self.dict objectForKey: name] 

    // I want to say: (pseudocode) 
    thecallback = [self.dict objectForKey: name]; 
    if (thecallback is of type "callbackWithOneParam") { 
     thecallback(@"some param") 
    } 
    else if (thecallback is of type "callbackWithTwoParams") { 
     thecallback(@"some param", [[NSObject alloc] init]); 
    } 
} 
+0

Tôi nghĩ rằng bạn không thể. Trong tình huống của bạn, bạn chỉ có thể để lại tham số bổ sung NSObject và đặt nil nếu bạn không sử dụng nó. – SAKrisT

+2

Trong ví dụ này, bạn nên sử dụng chữ ký nhất quán cho tất cả các khối trong từ điển. Mã trong mỗi khối sau đó có thể độc lập quyết định tham số nào sẽ được sử dụng hoặc bỏ qua. Bạn cũng phải truyền giá trị trả về từ '-objectForKey:' vào chữ ký khối của bạn trước khi bạn có thể gọi khối. Bạn cũng phải sao chép từng khối vào heap trước khi thêm nó vào từ điển. – Darren

+0

Darren bạn có thể giải thích về hai câu cuối cùng của mình, cảm ơn bạn! –

Trả lời

2

Thẳng thắn, nếu các cuộc gọi lại có các loại khác nhau, chúng phải nằm trong các khóa khác nhau. Tại sao không sử dụng các phím @"callbackWithOneParam"@"callbackWithTwoParams"? Đối với tôi, đó là cấp trên để có một "callback" chung chung cộng với một "loại" chìa khóa riêng biệt để cho bạn biết làm thế nào để giải thích gọi lại.

Nhưng điều này thực sự yêu cầu là sử dụng các đối tượng của lớp tùy chỉnh thay vì từ điển. Bạn đã vượt qua ranh giới nơi các đối tượng chung ngừng hoạt động thuận tiện và bắt đầu gây ra nhiều vấn đề hơn là chúng giải quyết.

+0

+1 để giới thiệu một lớp tùy chỉnh trong từ điển. – BergQuester

-1

chỉ cần kiểm tra xem tên có phải là "Foo" hoặc "Bar" không? có lẽ sẽ giống như nhiều công sức như kiểm tra các thông số chức năng, trong đó tôi có một cảm giác isnt tốt mà không có nó trong một số hình thức của lớp và đi

if ([myObject class] == [MyClass class]) 
+0

bạn thực sự nên sử dụng 'isKindOfClass:' hoặc 'isMemberClass:' cho mục đích này –

0

Khi gọi một khối bạn PHẢI biết loại đối số của nó. Trong trường hợp của bạn, nếu "tên" là không đủ để xác định những gì các đối số nên được tôi sẽ thêm một khóa "loại" mà sẽ cho tôi biết. Dưới đây là ví dụ:

// Callback dictionary 

_callbacks = @{ 
    @{@"name":@"foo", @"type":@(1), @"callback":^(int i) { NSLog(@"%d", i); }}, 
    @{@"name":@"bar", @"type":@(2), @"callback":^(int i, int j) { NSLog(@"%d", i+j); }}, 
    @{@"name":@"zap", @"type":@(3), @"callback":^(int i, int j, int k) { NSLog(@"%d", i+j+k); }}, 
    @{@"name":@"cab", @"type":@(4), @"callback":^(NSString *s) { NSLog(@"%lu",s.length); }}, 
    @{@"name":@"fog", @"type":@(5), @"callback":^(void) { NSLog(@"I can't see"); }} 
} 


-(void) invokeCallbackForName:(NSString*)name withArguments:(NSArray*)args { 

    NSDictionary *info = _callbacks[name]; 

    if (info != nil) { 
     id block = info[@"callback"]; 
     int type = [info[@"type"] intValue]; 
     switch (type) { 

      case 1: { 
       int arg1 = [args[0] intValue]; 
       ((void(^)(int)) block)(arg1); 
       break; 
      } 
      case 2: { 
       int arg1 = [args[0] intValue]; 
       int arg2 = [args[1] intValue]; 
       ((void(^)(int,int)) block)(arg1,arg2); 
       break; 
      } 
      case 3: { 
       int arg1 = [args[0] intValue]; 
       int arg2 = [args[1] intValue]; 
       int arg3 = [args[2] intValue]; 
       ((void(^)(int,int,int)) block)(arg1,arg2,arg3); 
       break; 
      } 
      case 5: { 
       NSString *arg1 = [args[0] intValue]; 
       ((void(^)(NSString*)) block)(arg1); 
       break; 
      } 
      default: 
       [NSExceptien raise:NSInvalidArgumentException format:@"Unsupported callback type"]; 

     } 
    } 
} 

Lưu ý rằng bạn bắt buộc phải bỏ khối tới đúng loại nếu không, có thể bạn sẽ bị lỗi chương trình. Đó là bởi vì khối phụ thuộc vào trình biên dịch để đặt các đối số trên ngăn xếp theo đúng thứ tự và cho phép bất kỳ kiểu trả về nào.

0

Cá nhân, tôi sử dụng khéo léo CTBlockDescription ...

CTBlockDescription cho phép bạn kiểm tra các khối bao gồm các đối số và biên dịch các tính năng thời gian khi chạy.

BOOL(^bk)(BOOL,id) = ^BOOL(BOOL ani, id obj) { return YES; }; 

[CTBlockDescription.alloc initWithBlock:bk].blockSignature.description; 

<NSMethodSignature: 0x253f080> 
    number of arguments = 3 
    frame size = 12 
    is special struct return? NO 
    return value: -------- -------- -------- -------- 
     type encoding (c) 'c' 
     flags {isSigned} 
     modifiers {} 
     frame {offset = 0, offset adjust = 0, size = 4, size adjust = -3} 
     memory {offset = 0, size = 1} 
    argument 0: -------- -------- -------- -------- 
     type encoding (@) '@?' 
     flags {isObject, isBlock} 
     modifiers {} 
     frame {offset = 0, offset adjust = 0, size = 4, size adjust = 0} 
     memory {offset = 0, size = 4} 
    argument 1: -------- -------- -------- -------- 
     type encoding (c) 'c' 
     flags {isSigned} 
     modifiers {} 
     frame {offset = 4, offset adjust = 0, size = 4, size adjust = -3} 
     memory {offset = 0, size = 1} 
    argument 2: -------- -------- -------- -------- 
     type encoding (@) '@' 
     flags {isObject} 
     modifiers {} 
     frame {offset = 8, offset adjust = 0, size = 4, size adjust = 0} 
     memory {offset = 0, size = 4} 

Gorgeous ...

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