使用GCD创建循环

时间:2012-06-12 14:12:18

标签: iphone objective-c objective-c-blocks grand-central-dispatch

所以这就是我所拥有的:

  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
                }
            });

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

3 个答案:

答案 0 :(得分:4)

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

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

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

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

这也提供了一个方便的取消钩子;只需在实例中添加一个BOOL,指示下一次调用是否应该执行任何操作并重新安排。

答案 1 :(得分:3)

杰弗里·托马斯的答案很接近,但是在ARC下,它会泄漏阻塞,没有ARC,它会崩溃。

如果没有ARC,__block变量不会保留它引用的内容。块在堆栈上创建。所以callback变量指向堆栈上的块。第一次(在块之外)将callback传递给dispatch_after时,dispatch_after成功地在堆上复制了块。但是当调用该副本并再次将callback传递给dispatch_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并使用适合你的内存管理的分支。

答案 2 :(得分: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 Tips & Tricks