Tôi có một biến với một khối chấp nhận một số đối số. Số lượng đối số chính xác và các loại đối số của chúng có thể thay đổi. Ví dụ nó có thể là một khốiChặn cuộc gọi với các đối số từ va_list khi số đối số và loại của khối có thể thay đổi
void(^testBlock1)(int) = ^(int i){}
hoặc một khối
void(^testBlock2)(NSString *,BOOL,int,float) = ^(NSString *str,BOOL b,int i,float f){}
loại Đối số được giới hạn {id, BOOL, char, int, unsigned int, float}
.
Tôi biết số lượng đối số hiện tại và loại đối số của chúng. Tôi cần phải thực hiện một phương pháp mà có thể thực hiện khối với lập luận đưa ra:
-(void)runBlock:(id)block withArguments:(va_list)arguments
types:(const char *)types count:(NSUInteger)count;
tôi có một giải pháp làm việc ngây thơ, nhưng nó là khá xấu xí, hỗ trợ các loại duy nhất của không có kích thước hơn 4 byte và dựa trên sự liên kết. Vì vậy, tôi đang tìm kiếm một cái gì đó tốt hơn. Giải pháp của tôi là một cái gì đó như:
#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;
}
}
Cảm ơn bạn đã trả lời. Tôi đã có danh sách các đối số và loại của chúng. Và có, tôi có thể tìm và lấy con trỏ hàm _invoke_. Nhưng làm thế nào tôi có thể đặc biệt gọi nó trong một cách tốt hơn so với các macro 'BLOCK_ARG (N)' của tôi để đúc và một mảng tạm thời cho các đối số? Có giải pháp nào khác ngoại trừ 'ffi_call'? Sử dụng ** libffi ** trông quá chi phí cho công việc nhỏ của tôi. – Yan
Vâng đây là điều - bạn phải sử dụng lắp ráp để thiết lập các thông số theo cách C mong đợi. Đó là những gì NSInvocation và các ruột khác của thời gian chạy Objective-C làm bởi vì trong C các đối số phải được đặt ra trong các thanh ghi cụ thể, tràn vào ngăn xếp theo một cách nào đó. Điều đó thay đổi dựa trên nền tảng (x86, x64, ARM). – russbishop