adi*_*dib 27 oop closures introspection objective-c objective-c-blocks
这主要是好奇心,我不确定这是什么实际用途,但这里有.
由于块也是Objective-C对象,是否可以检查它们的类型?也就是说,它是否响应isKindOfClass:
消息以及如何对块使用该消息?
我的天真认为它可能是这样的:
-(void) aMethod {
typedef int (^BlockA)(int x, int y);
id blockVar = ...; // get a block from somewhere
if([blockVar isKindOfClass:BlockA]) {
BlockA blockVarA = blockVar;
int result = blockVarA(1,2);
}
}
Run Code Online (Sandbox Code Playgroud)
上面的代码可能不起作用.但是,如果它是可以检查块的类型,什么是做了正确的方法是什么?
Cla*_*ges 42
可以做,有点儿.
但首先,让我们消除歧义.-[NSObject isKindOfClass:]
可以告诉你这是一个块,这就是它.例如,我相信这一行代码 - 表面上和不幸的是A BAD IDEA - 将为当前Lion和iOS 5.x上的块返回YES:
[myBlock isKindOfClass:NSClassFromString(@"NSBlock")]
Run Code Online (Sandbox Code Playgroud)
这无助于您区分块的功能签名.
但是可以通过从块的文档内部结构中剔除签名来完成它.代码遵循示例OS X命令行应用程序,其中大部分都是从Mike Ash的MABlockClosure中删除的(非常详细的解释).(更新: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;
}
Run Code Online (Sandbox Code Playgroud)
运行这个,你应该得到类似的东西:
[58003:403] signature i16@?0@8
[58003:403] __NSCFNumber 42
[58003:403] retval 42
Run Code Online (Sandbox Code Playgroud)
签名中的数字(我被告知它们是偏移的)可以被剥离以便更简单i@?@
.
签名是在@encode格式,这是不完美的(例如,大多数对象映射到相同的@
),而应该给予你一些在运行时来区分不同的签名块的能力.
虽然它没有在Apple链接中记录,但我的测试指出@?
是块类型的代码,这可以理解上面的签名.我找到了一个关于这个问题的开发人员讨论,这似乎支持了这一点.
Fab*_*ser 11
" BlockA
"in (^BlockA)
是变量名(在本例中为typedef),而不是其类.
块是对象,但不是常规的子类NSObject
.它们只实现方法的子集.-isKindOfClass:
可能会崩溃.
块是类型NSMallocBlock
或NSConcreteGlobalBlock
,...取决于它们的创建位置(堆,堆栈,...).
看来块是像类__NSGlobalBlock__
,__NSStackBlock__
或__NSMallocBlock__
等,其继承链最终去NSBlock
,然后NSObject
.所以你可以通过测试来测试某些东西是否是块[... isKindOfClass:NSClassFromString(@"NSBlock")]
.但是,似乎没有任何方法可以在运行时查询块的签名(返回类型和参数类型),因此您将无法区分不同签名的块.
归档时间: |
|
查看次数: |
7879 次 |
最近记录: |