可以,有点。
但首先,让我们消除歧义。 -[NSObject isKindOfClass:] 可以告诉你这是一个障碍,仅此而已。例如。我相信这行代码——表面上很不幸地是A BAD IDEA——对于当前的 Lion 和 iOS 5.x 上的块将返回 YES:
[myBlock isKindOfClass:NSClassFromString(@"NSBlock")]
这不会帮助您区分块的功能签名。
但是可以通过从块的记录内部结构中获取签名来完成。下面是一个示例 OS X 命令行应用程序的代码,其中大部分来自 Mike Ash 的MABlockClosure(很棒的detailed explanation)。 (更新:Github 项目 CTObjectiveCRuntimeAdditions 显然也为此目的提供了库代码。)
#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 格式,这并不完美(例如,大多数对象映射到相同的@),但应该让您一些能够区分具有不同签名的块运行时。
虽然 Apple 链接中没有记录,但我的测试指向 @? 是块类型的代码,这对上面的签名很有意义。我在这个问题上找到了一个clang-developers discussion,这似乎支持了这一点。