いくつかの引数を受け入れるブロックを持つ変数があります。引数の正確な数とそのタイプは異なる場合があります。たとえば、ブロックにすることができます
void(^testBlock1)(int) = ^(int i){}
またはブロック
void(^testBlock2)(NSString *,BOOL,int,float) = ^(NSString *str,BOOL b,int i,float f){}
引数の種類はに制限されてい{id, BOOL, char, int, unsigned int, float}
ます。
引数の現在の数とそのタイプを知っています。与えられた引数でブロックを実行できるメソッドを実装する必要があります:
-(void)runBlock:(id)block withArguments:(va_list)arguments
types:(const char *)types count:(NSUInteger)count;
私には実用的な素朴な解決策が1つありますが、それは非常に醜く、4バイト以下のサイズのタイプのみをサポートし、アライメントに依存しています。だから私はもっと良いものを探しています。私の解決策は次のようなものです:
#define MAX_ARGS_COUNT 5
-(void)runBlock:(id)block withArguments:(va_list)arguments
types:(const char *)types count:(NSUInteger)count{
// We will store arguments in this array.
void * args_table[MAX_ARGS_COUNT];
// Filling array with arguments
for (int i=0; i<count; ++i) {
switch (types[i]) {
case '@':
case 'c':
case 'i':
case 'I':
args_table[i] = (void *)(va_arg(arguments, int));
break;
case 'f':
*((float *)(args_table+i)) = (float)(va_arg(arguments, double));
break;
default:
@throw [NSException exceptionWithName:@"runBlock" reason:[NSString stringWithFormat:@"unsupported type %c",types[i]] userInfo:nil];
break;
}
}
// Now we need to call our block with appropriate count of arguments
#define ARG(N) args_table[N]
#define BLOCK_ARG1 void(^)(void *)
#define BLOCK_ARG2 void(^)(void *,void *)
#define BLOCK_ARG3 void(^)(void *,void *,void *)
#define BLOCK_ARG4 void(^)(void *,void *,void *,void *)
#define BLOCK_ARG5 void(^)(void *,void *,void *,void *,void *)
#define BLOCK_ARG(N) BLOCK_ARG##N
switch (count) {
case 1:
((BLOCK_ARG(1))block)(ARG(0));
break;
case 2:
((BLOCK_ARG(2))block)(ARG(0),ARG(1));
break;
case 3:
((BLOCK_ARG(3))block)(ARG(0),ARG(1),ARG(2));
break;
case 4:
((BLOCK_ARG(4))block)(ARG(0),ARG(1),ARG(2),ARG(3));
break;
case 5:
((BLOCK_ARG(5))block)(ARG(0),ARG(1),ARG(2),ARG(3),ARG(4));
break;
default:
break;
}
}