Search code examples
iosobjective-cblockintrospection

iOS Blocks introspection


I would like to know two things:

1- Is it possible by using objective-c introspection to know the return type of a block.

For example: int (^CountBlock)(NSArray *array) I would like to know the type it will be returning is int.

The second question is:

2- Can I hold a reference to a generic block? What I mean with this, is basically can I do something like id myBlock and with this answer the first question.

What I tried

This kind of stuff is not possible:

id aBlock = ^{

    NSString * aString = @"OMG";

    return aString;
};

aBlock();

As the compiler sees that the id aBlock is not a function or a function pointer.


Solution

  • 1) This answer talks about how to grab the signature of a block. Here's the relevant code:

    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];
    }
    

    It's really not ideal, since you just get the @encode string of the signature, which looks like this: @"i16@?0@8". I'd love to see if someone has a better approach.

    2) You can definitely cast blocks to and from type id:

    typedef void(^MyBlockType)(void);
    id aBlock = ^ { };
    ((MyBlockType)aBlock)();
    

    Of course, if you cast to the wrong block type, you'll end up with undefined behavior.