ブロックを引数として受け入れる変数があります。正確な数の引数とその型は異なる場合があります。例えば、それはブロックの引数の数と型が変わる可能性がある場合、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;
私は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;
}
}
ありがとうございました。 私はすでに引数とその型のリストを持っています。そして、はい、_invoke_関数ポインタを見つけて取得できます。しかし、どうすればキャストのための 'BLOCK_ARG(N)'マクロと引数のための一時的な配列よりも優れた方法で呼び出すことができますか? 'ffi_call'以外の解決策はありますか? ** libffi **を使用することは私の小さな仕事のオーバーヘッドにすぎません。 – Yan
さて、ここでは、Cが期待する方法でパラメータを設定するためにアセンブリを使用する必要があります。これは、Objective-CランタイムのNSInvocationやその他のさまざまな欠点が、C言語では特定のレジスタに配置されなければならず、特定の方法でスタックに流出するためです。これはプラットフォーム(x86、x64、ARM)に基づいて変わります。 – russbishop