4

假设我有一个包含块的数组,我需要断言它们都期望给定数量的参数。

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

4

2 回答 2

7

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

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

Mike Ash 的MABlockForwarding 项目就是这样做的(另请参阅文章)——该文件顶部的大部分内容是从 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)),一个描述块的返回和参数类型的类型编码字符串。从那里,您可以创建一个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,因为它包含块本身的隐藏参数(并且块不使用隐藏_cmd参数,否则它将是 4)。

于 2012-07-19T18:43:59.403 回答
1

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

搜索您发送到此处的 Intropection

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

于 2012-07-19T13:40:01.390 回答