【问题标题】:ARC __bridge cast Block_copy & Block_releaseARC __bridge cast Block_copy & Block_release
【发布时间】:2012-03-14 12:24:26
【问题描述】:

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

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. 我必须强制转换为 void * 的论点,这不是很讽刺吗? 阻止_复制?
  2. 为什么编译器在阻塞时对我的 Block_release 感到满意 在没有桥 void * cast 的 Block_copy 上?

代码似乎可以工作,我没有检测到泄漏或过早发布,但我对语法有点困惑......

【问题讨论】:

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


    【解决方案1】:

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

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

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

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

    dispatch_async(dispatch_get_main_queue(), resizer);
    

    【讨论】:

    • 答案很明确。我还建议 @verec 在主队列中使用 dispatch_async。
    【解决方案2】:

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

    嗯,这就是你得到dispatch_after 的原因。如果你提供一个很小的时间值,它就会产生你想要的效果:你给一个块,这个块将在当前运行循环结束并且重绘时刻发生后立即执行。

    或者,如果您可以不坚持阻塞,请使用performSelector:withObject:afterDelay:,延迟值很小(甚至为零)。效果是一样的。

    您所要求的称为“延迟性能”并且很常见。所以用通用的方式,框架给你的方式;不要像你的代码那样试图变得怪异和花哨。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-17
      • 2012-12-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多