我有一个块接受一些参数的变量。参数的精确数量及其类型可能会有所不同。例如,它可以是嵌段当块的参数数量和类型可以变化时,调用来自va_list参数的块
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;
我有一个工作天真的解决方案,但它是相当难看,只支持类型不超过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;
}
}
谢谢你的回答。 我已经有参数列表和它们的类型。是的,我可以找到并获取_invoke_函数指针。但是我怎么能特别以比我的'BLOCK_ARG(N)'宏更好的方式来调用它,以及用于参数的临时数组呢?除了'ffi_call'之外,还有其他解决方案吗?使用** libffi **对于我的小任务看起来太高了。 – Yan
嗯,这是事情 - 你必须使用程序集来设置C预期的参数。这就是NSInvocation和Objective-C运行库的其他许多内容,因为在C中,参数必须在某些寄存器中进行布局,并以某种方式溢出到堆栈上。这种变化基于平台(x86,x64,ARM)。 – russbishop