When you call a block, you MUST know the type of its arguments. In your case, if the โnameโ is not enough to determine what arguments should be, I would add another key โtypeโ that will tell me. Here is an example:
// 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"]; } } }
Note that you need the block to be bound to the correct type, otherwise you are likely to run into your program. This is because the block depends on the compiler to push the arguments onto the stack in the correct order and allow any return type.
aLevelOfIndirection
source share