This is really possible for any recent version of Clang.
Apple ABI for blocks is private, but also published . Since this document tells us the layout that the compiler will use for the Block object, we can duplicate this information in the header file and use it to access the components of the block.
Mike Ash The MABlockForwarding project does just that (see also the article ) - most of the material at the top of this file is a copy in an ABI document. What he created, in which we are interested, is the BlockSig() function:
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]; }
which will be returned (for blocks that have it (which they all do with the recent Clang)), enter an encoding string describing the block return and argument types. From there, you can create an NSMethodSignature object and request its 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];
The result is 3 because it contains a hidden argument for the block itself (and the blocks do not use the hidden argument _cmd or it will be 4).
source share