Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cast blocks to and from void *

So, I'm trying to pass a block as an NSAlert contextInfo parameter.

[myAlert beginSheetModalForWindow: theWindow
                    modalDelegate: myAlert
                   didEndSelector: @selector(alertDidEnd:returnCode:contextInfo:)
                      contextInfo: (void *) aBlock];

and get it back on the other end:

void (^responseBlock)() = (__bridge_transfer void (^)()) contextInfo;

Which works, to an extent. Before my call to beginSheetModalForWindow:... aBlock is at 0x00007fff610e1ec0, and in the response (alertDidEnd:...), contextInfo is at 0x00007fff610e1ec0.

However, when I try to call the block:

responseBlock();

I get the following error

error: called object type '__block_literal_generic *' is not a function or function pointer
error: 1 errors parsing expression

How does one properly cast blocks to an from void *s for the sake of simple transference?

Edit: Full attempted code, using the cast methods suggested in the answers. I now receive an EXC_BAD_ACCESS error on the responseBlock(); call.

- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
    void (^responseBlock)() = (__bridge typeof(responseBlock)) contextInfo;

    switch (returnCode)
    {
        case NSCancelButton:
        {
            break;
        }
        
        case NSOKButton:
        {
            responseBlock();
            break;
        }
    }
}

Other Notes: When using __bridge, the memory address of responseBlock and contextInfo are different, whereas with __bridge_transfer, they are the same. Neither alleviates the EXC_BAD_ACCESS issue.

WORKING:

[myAlert beginSheetModalForWindow: theWindow
                    modalDelegate: myAlert
                   didEndSelector: @selector(alertDidEnd:returnCode:contextInfo:)
                      contextInfo: (__bridge_retained void *) [aBlock copy]];

and later...

void (^responseBlock)() = (__bridge_transfer typeof(responseBlock)) contextInfo;
like image 544
Patrick Perini Avatar asked Jun 19 '12 17:06

Patrick Perini


1 Answers

Here's a small example. I think that the problem with your code is that you are trying to use __bridge_transfer with a void * which isn't memory managed with ARC:

void takesBlock(void *asPointer)
{
    void (^asBlock)() = (__bridge typeof asBlock) asPointer;

    asBlock();
}

int main()
{
    @autoreleasepool {
        takesBlock((__bridge void *)[^{
            NSLog(@"Hello World!");
        } copy]);
    }
}
like image 130
Richard J. Ross III Avatar answered Sep 23 '22 18:09

Richard J. Ross III