Ho una variabile con un blocco che accetta alcuni argomenti. Il numero esatto di argomenti e i loro tipi possono variare. Ad esempio può essere un bloccoBlocco di chiamata con argomenti da va_list quando gli argomenti del blocco numero e tipi possono variare
void(^testBlock1)(int) = ^(int i){}
o un blocco
void(^testBlock2)(NSString *,BOOL,int,float) = ^(NSString *str,BOOL b,int i,float f){}
tipi di argomenti sono limitati a {id, BOOL, char, int, unsigned int, float}
.
Conosco il conteggio corrente degli argomenti e dei relativi tipi. Ho bisogno di implementare un metodo che può eseguire il blocco con determinati argomenti:
-(void)runBlock:(id)block withArguments:(va_list)arguments
types:(const char *)types count:(NSUInteger)count;
ho una soluzione di lavoro ingenuo, ma è abbastanza brutto, supporta solo i tipi di alcuna dimensione più di 4 byte e si basa sull'allineamento. Quindi sto cercando qualcosa di meglio. La mia soluzione è qualcosa di simile:
#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;
}
}
Grazie per la risposta. Ho già la lista degli argomenti e dei loro tipi. E sì, posso trovare e prendere il puntatore a funzione _invoke_. Ma come posso in particolare definirlo meglio delle mie macro 'BLOCK_ARG (N)' per la trasmissione e una matrice temporanea per gli argomenti? C'è qualche altra soluzione tranne come 'ffi_call'? L'uso di ** libffi ** sembra troppo sovraccarico per il mio piccolo compito. – Yan
Bene, ecco la cosa: devi usare l'assembly per impostare i parametri nel modo in cui C si aspetta. Questo è ciò che NSInvocation e altri budella del runtime Objective-C fanno perché in C gli argomenti devono essere disposti in certi registri, riversandosi nello stack in un certo modo. Questo cambia in base alla piattaforma (x86, x64, ARM). – russbishop