Can do,有点像。
但首先,让我们消除歧义。-[NSObject isKindOfClass:]
可以告诉你这是一个块,仅此而已。例如。我相信this一行代码——表面上但不幸的是一个坏主意-- 对于当前 Lion 和 iOS 5.x 上的块将返回 YES:
[myBlock isKindOfClass:NSClassFromString(@"NSBlock")]
这不会帮助您区分块的函数签名。
但这可以通过从块记录的内部结构中获取签名来完成。下面是一个示例 OS X 命令行应用程序的代码,其中大部分内容摘自 Mike Ash 的MA区块关闭 https://github.com/mikeash/MABlockClosure (great detailed解释 http://www.mikeash.com/pyblog/friday-qa-2011-05-06-a-tour-of-mablockclosure.html)。 (更新:Github 项目CTObjectiveCRuntimeAdditions https://github.com/ebf/CTObjectiveCRuntimeAdditions#getting-runtime-information-about-blocks显然也为此目的提供了库代码。)
#import <Foundation/Foundation.h>
struct BlockDescriptor {
unsigned long reserved;
unsigned long size;
void *rest[1];
};
struct Block {
void *isa;
int flags;
int reserved;
void *invoke;
struct BlockDescriptor *descriptor;
};
static const char *BlockSig(id blockObj)
{
struct Block *block = (void *)blockObj;
struct BlockDescriptor *descriptor = block->descriptor;
int copyDisposeFlag = 1 << 25;
int signatureFlag = 1 << 30;
assert(block->flags & signatureFlag);
int index = 0;
if(block->flags & copyDisposeFlag)
index += 2;
return descriptor->rest[index];
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
int (^block)(NSNumber *) = ^(NSNumber *num) {
NSLog(@"%@ %@", NSStringFromClass([num class]), num);
return [num intValue];
};
NSLog(@"signature %s", BlockSig(block));
NSLog(@"retval %d", (int)block([NSNumber numberWithInt:42]));
}
return 0;
}
运行这个,你应该得到类似的结果:
[58003:403] signature i16@?0@8
[58003:403] __NSCFNumber 42
[58003:403] retval 42
签名中的数字(我听说它们是偏移量)可以被删除以更简单i@?@
.
签名位于@encode https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html格式,这并不完美(例如,大多数对象映射到相同的@
),但应该负担得起some能够在运行时区分具有不同签名的块。
虽然苹果链接中没有记录,但我的测试指出@?
是块类型的代码,这使得上面的签名有意义。我找到了一个 clang 开发者讨论 http://clang-developers.42468.n3.nabble.com/PATCH-add-unconditional-support-for-encode-block-descriptor-string-td216512.html在这个问题上,这似乎支持了这一点。