ARC __bridge cast Block_copy& Block_release

时间:2012-03-14 12:24:27

标签: objective-c ios automatic-ref-counting

出于某种原因,我想在运行循环的下一次迭代期间执行一个块,所以我想出了:

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. 讽刺性的是,我必须抛弃无效的论据 阻止 _copy?
  2. 为什么编译器在阻塞时对我的Block_release感到满意 在Block_copy上没有桥空*演员?
  3. 代码似乎有效,我没有发现泄漏也没有发现过早发布,但我对语法感到有些困惑......

2 个答案:

答案 0 :(得分:13)

块被视为对象,因此ARC会阻止您在没有显式桥接转换的情况下将它们转换为void *。奇怪的是你的编译器没有在Block_release上抱怨:它应该(在我的机器上,它确实如此)。

由于ARC将块视为对象,因此您不再需要使用Block_copyBlock_release。当您希望它移动到堆并让编译器管理剩余部分时,复制块(带-[NSObject copy])。

-[NSObject performSelectorOnMainThread:withObject:waitUntilDone:]保留接收者和参数对象,直到调用该方法。因此,您的块将在需要时保留并释放。您所要做的就是通过在将copy消息传递给方法之前发送dispatch_async(dispatch_get_main_queue(), resizer); 消息来确保该块不存储在堆栈中。

此外,有一种更简单的方法来分配块的执行:它是libdispatch(又名GCD)。

{{1}}

答案 1 :(得分:4)

  

我希望在下一次运行循环迭代期间执行一个块

嗯,这就是你dispatch_after的原因。如果你提供一个很小的时间值,它将具有你所追求的效果:你给出一个块,并且当当前的runloop完成并且重绘时刻已经发生时块将执行。

或者,如果您可以在不坚持阻止的情况下生活,请使用具有微小延迟值的performSelector:withObject:afterDelay:(甚至为零)。这有同样的效果。

你所要求的是“延迟表现”并且很常见。所以这是常见的方式,框架给你的方式;不要试图像你的代码那样变得奇怪和幻想。