4

所以这就是我所拥有的:

  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), ^{
                bool ready = some_function();
                if( ready ) {                    
                   do_smth_here()
                } else {
                   //invoke this block one more time after 0.1 sec
                }
            });

问题是如何获得对当前块的引用?

4

3 回答 3

4

我通常不会跳过上面显示的循环,而是声明一个我可以调用的实例方法,在内部,它会根据需要处理重新触发。这样,任何给定的块都是一次性的,但重新触发会创建一个新块。

只要块的创建不是非常昂贵——如果状态来自封装实例方法的任何东西就不会那么昂贵——它就足够高效并且简单得多。

- (void) retriggerMethod
{
     ... do stuff here, assuming you want to do it on first invocation ...
     dispatch_after( ..., ^{
         [self retriggerMethod];
     });
}

您可以根据需要对其进行重组。如果您想防止同时重新触发等,您可以轻松添加 BOOL 实例变量......

这也为取消提供了方便的钩子;只需向实例添加一个 BOOL ,指示下一次调用是否真的应该做任何事情并重新安排。

于 2012-06-12T21:49:14.320 回答
3

Jeffrey Thomas 的答案很接近,但是在 ARC 下,它会泄漏块,而没有 ARC,它会崩溃。

如果没有 ARC,__block变量就不会保留它所引用的内容。块是在堆栈上创建的。所以callback变量指向堆栈上的一个块。当您第一次传递callbackdispatch_after(块外)时,dispatch_after成功地在堆上制作了块的副本。但是,当该副本被调用并再次传递callbackdispatch_after时,callback是一个悬空指针(指向堆栈上现在已销毁的块),并且dispatch_after(通常)会崩溃。

使用 ARC,__block块类型的变量(如callback)会自动将块复制到堆中。所以你不会遇到崩溃。但是对于 ARC,__block变量会保留它引用的对象(或块)。这导致了一个保留周期:块引用自身。Xcode 将在递归dispatch_after调用中向您显示警告:“在此块中强烈捕获'回调'可能会导致保留周期”。

要解决这些问题,您可以显式复制块(将其从堆栈移动到 MRC 下的堆)并设置callback为 nil(在 ARC 下)或释放它(在 MRC 下)以防止泄漏:

    __block void (^callback)() = [^{
        if(stop_) {
            NSLog(@"all done");
#if __has_feature(objc_arc)
            callback = nil; // break retain cycle
#else
            [callback release];
#endif
        } else {
            NSLog(@"still going");
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
        }
    } copy];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);

显然,您可以删除#if并只使用适合您的内存管理的分支。

于 2012-06-12T20:12:31.313 回答
1

我认为这是您正在寻找的代码:

__block void (^callback)();
callback = ^{
    bool ready = some_function();
    if( ready ) {
        do_smth_here()
    } else {
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);
    }
};

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1*NSEC_PER_SEC), dispatch_get_current_queue(), callback);

感谢^ Blocks 提示和技巧

于 2012-06-12T16:17:46.300 回答