2012-11-22 39 views
7

就我而言,這與其他的「我可以檢查塊的類型」帖子有什麼不同?Objective-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

我覺得你不能。在你的情況下,你可以留下額外的參數NSObject,如果你不使用它,則放入nil。 – SAKrisT

+2

在這個例子中,對字典中的所有塊使用一致的簽名更加可取。每個塊內的代碼可以獨立決定哪些參數將被使用或忽略。在調用塊之前,還必須將'-objectForKey:'的返回值轉換爲塊簽名。在將其添加到字典之前,您還必須將每個塊複製到堆中。 – Darren

+0

Darren能否詳細說明你的最後兩條語句,謝謝! –

回答

2

坦率地說,如果回調有不同的類型,它們應該在不同的密鑰下。爲什麼不使用鑰匙@"callbackWithOneParam"@"callbackWithTwoParams"?對我來說,這比擁有通用的「回調」鍵和一個單獨的「類型」鍵來告訴你如何解釋回調更爲優越。

但這真正需要的是使用自定義類的對象而不是字典。你已經越過了通用對象不再方便的邊界,並開始導致比他們解決的問題更多的問題。

+0

+1用於在字典上推薦自定義類。 – BergQuester

-1

只是檢查名稱是「Foo」還是「Bar」?可能是一樣多的努力作爲檢查功能的參數,這是我的心不是可能的一種感覺,而不必以某種形式的類中去

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

您真的應該使用'isKindOfClass:'或'isMemberClass:'爲此目的 –

0

在調用塊時,你必須知道它的參數的類型。在你的情況下,如果「名稱」不足以確定參數應該是什麼,我會添加另一個關鍵「類型」,這將告訴我。這裏是一個例子:

// 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"]; 

     } 
    } 
} 

請注意,您必須將塊轉換爲正確的類型,否則您可能會讓程序崩潰。這是因爲該塊依賴於編譯器將參數按正確的順序放入堆棧並允許任何返回類型。

0

就個人而言,我用的巧妙CTBlockDescription ...

CTBlockDescription讓您檢查模塊,包括參數,並在運行時編譯時的功能。

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} 

華麗...