ARC __bridge cast Block_copy & Block_release

2019-02-18 10:11发布

For some reason I want a block to execute during the next iteration of the run loop, so I came up with:

typedef void (^resizer_t)() ;

- (void) applyResizer: (resizer_t) resizer {
    resizer() ;
    Block_release(resizer) ;
}

- (void) usage {
    ...
    resizer_t resizer = ^() {
        // stuff
    } ;

    [self performSelectorOnMainThread:@selector(applyResizer:)
                           withObject:(__bridge id) Block_copy((__bridge void *) resizer)
                        waitUntilDone:NO] ;
}
  1. Isn't it ironic that I have to cast to void * the argument to Block_copy ?
  2. Why is the compiler happy with my Block_release when it chokes on Block_copy without the bridge void * cast?

The code seems to work, I didn't detect a leak nor a premature release, but I'm a bit puzzled by the syntax ...

2条回答
Explosion°爆炸
2楼-- · 2019-02-18 10:23

I want a block to execute during the next iteration of the run loop

Well, that's why you've got dispatch_after. If you supply a tiny time value, it will have exactly the effect you're after: you give a block, and the block will execute as soon the current runloop finishes and the redraw moment has happened.

Or if you can live without insisting on a block, use performSelector:withObject:afterDelay: with a tiny delay value (even zero). That has the same effect.

What you're asking for is called "delayed performance" and is very common. So do it the common way, the way the framework gives you; don't try to get all weird and fancy like your code is doing.

查看更多
Bombasti
3楼-- · 2019-02-18 10:36

Block are treated as objects so ARC prevent you from casting them to void * without explicit bridged cast. It strange that your compiler doesn't complain on Block_release: it should (on my machine, it does).

Because ARC treats block as objects, you shouldn't need to use Block_copy nor Block_release anymore. Copy the block (with -[NSObject copy]) when you want it to move to the heap and let the compiler manage the remainder.

-[NSObject performSelectorOnMainThread:withObject:waitUntilDone:] retains the receiver and the parameter object until the method is invoked. So your block will be retained and released when required. All you have to do is ensure that the block isn't stored on the stack by sending the copy message before passing it to the method.

Moreover, there is a simpler way to dispatch the execution of a block: it's libdispatch (aka GCD).

dispatch_async(dispatch_get_main_queue(), resizer);
查看更多
登录 后发表回答