Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 585
Rui Peres Avatar asked Dec 18 '13 14:12

Rui Peres


2 Answers

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.

like image 81
godel9 Avatar answered Oct 23 '22 10:10

godel9


I think the problem for number 2 is that blocks are named as part of the type definition, e.g.

void (^blockName)(void) = ^{};

A workaround is to define a generic block type:

typedef void(^BlockType)(void);
BlockType myBlock = ^{};
myBlock();

edit: pointed out by @neilco, a much simpler way using dispatch block types (which return nothing and accept no arguments):

dispatch_block_t myBlock = ^{};
myBlock();
like image 1
wattson12 Avatar answered Oct 23 '22 09:10

wattson12