找出一个块需要多少个参数

时间:2012-07-19 13:22:42

标签: objective-c objective-c-blocks

让我们说我有一个包含Blocks的数组,我需要声明所有人都期望给定数量的参数。

有没有办法以编程方式找到它?

2 个答案:

答案 0 :(得分:7)

对于任何最新版本的Clang来说,这确实是可能的。

Apple ABI for Blocks是私有的,但也是published。由于该文档告诉我们编译器将用于Block对象的布局,我们可以在头文件中复制该信息并使用它来访问Block的组件。

Mike Ash的MABlockForwarding project就是这样做的(另请参阅article) - 此文件顶部的大部分内容都是来自ABI文档的复制粘贴。他创建的我们感兴趣的是BlockSig()函数:

static const char *BlockSig(id blockObj)
{
    struct Block *block = (__bridge void *)blockObj;
    struct BlockDescriptor *descriptor = block->descriptor;

    assert(block->flags & BLOCK_HAS_SIGNATURE);

    int index = 0;
    if(block->flags & BLOCK_HAS_COPY_DISPOSE)
        index += 2;

    return descriptor->rest[index];
}

将返回(对于拥有它的块(它们都使用最近的Clang),一个type encoding string描述了Block的返回和参数类型。从那里,您可以创建一个NSMethodSignature对象,并询问它的numberOfArguments

 NSString * (^block)(int, NSArray *) = ^NSString * (int i, NSArray * a){
        return @"Oh, yeah!";
 };
 const char * types = BlockSig(block);
 NSMethodSignature * sig = [NSMethodSignature signatureWithObjCTypes:types];
 [sig numberOfArguments];

结果有3,因为它包含Block本身的隐藏参数(而Blocks不使用隐藏的_cmd参数,或者它将是4)。

答案 1 :(得分:1)

答案是你不能。请参阅Mike Ash关于此页面的评论:

{p> Search for Intropection sends you here

那么,你真正的问题是什么?如果正确构造参数,则可以确保系统正常运行。例如,您可以使用C ++对参数的默认值执行的操作,并将每个块转换为采用最大args数的类型,并始终在堆栈上推送那么多项。或者你总是可以让第一个参数是你在堆栈上推送的参数数量。如果您推送对象而不是数字/指针,那么您可以查看每个参数的类并动态调整。