块一旦被复制,就会成为 NSBlock 的实例,这意味着我们可以使用运行时向它添加各种好东西。这是一个例子:
@protocol QuietTheCompiler<NSObject>
- (NSString*) prettyBlockDescription;
@end
static id beautifyBlockDescription(id block, NSString *name)
{
static void *kAssocObjectPrettyBlockDescription = "A";
Class blockClass = [block class];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL descrSel = @selector(description);
SEL prettySel = @selector(prettyBlockDescription);
Method descrMethod = class_getInstanceMethod(blockClass, descrSel);
IMP originalImpl = class_getMethodImplementation(blockClass, descrSel);
IMP prettyImpl = imp_implementationWithBlock(^(id self_) {
id value = objc_getAssociatedObject(self_, kAssocObjectPrettyBlockDescription);
return (value != nil)? value : originalImpl(self_, descrSel);
});
if (class_addMethod(blockClass, prettySel, prettyImpl, method_getTypeEncoding(descrMethod))) {
IMP newImpl = imp_implementationWithBlock(^(id self_) {
return [self_ prettyBlockDescription];
});
class_replaceMethod(blockClass, descrSel, newImpl, method_getTypeEncoding(descrMethod));
}
});
NSString *description = [NSString stringWithFormat:@"<%@: %p name=%@>",NSStringFromClass(blockClass),block,name];
objc_setAssociatedObject(block, kAssocObjectPrettyBlockDescription, description, OBJC_ASSOCIATION_RETAIN);
return block;
}
int main (int argc, const char * argv[])
{
@autoreleasepool {
int (^block1)(int,NSString*) = ^(int i, NSString *fmt) {
return i;
};
id blockObject1 = beautifyBlockDescription([block1 copy], @"Hello");
int (^block2)(int,NSString*) = ^(int i, NSString *fmt) {
return i+1;
};
id blockObject2 = [block2 copy];
NSLog(@"Block 1: %@", blockObject1);
NSLog(@"Block 1: %@", blockObject2);
}
return 0;
}
这是该程序的输出:
// Sample Output
2013-03-31 12:34:48.984 Dummy[1231:303] Block 1: <__NSGlobalBlock__: 0x1000059d0 name=Hello>
2013-03-31 12:34:48.987 Dummy[1231:303] Block 1: <__NSGlobalBlock__: 0x100005a10>
我建议您将 beautifyBlockDescription 函数包装在一个宏中,以便对于发布代码它只返回块。