如何“突破”dispatch_apply()?

时间:2010-06-23 21:09:27

标签: objective-c cocoa break objective-c-blocks grand-central-dispatch

有没有办法模拟dispatch_apply()块中的break语句?

例如,我见过处理枚举块的每个Cocoa API都有一个“停止”参数:

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger i, BOOL *stop) {
    if ([obj isNotVeryNice]) {
        *stop = YES; // No more enumerating!
    } else {
        NSLog(@"%@ at %zu", obj, i);
    }
}];

GCD有类似内容吗?

3 个答案:

答案 0 :(得分:14)

按照设计,dispatch_*() API没有取消的概念。这样做的原因是因为几乎普遍认为你的代码维护了何时停止或不停止的概念,因此,也支持在dispatch _ *()中API将是多余的(并且冗余会带来错误)。 / p>

因此,如果您想“提前停止”或以其他方式取消调度队列中的待处理项目(无论它们如何排队),您可以通过与允许您取消的排队块共享一些状态来实现

if (is_canceled()) return;

或者:

__block BOOL keepGoing = YES;
dispatch_*(someQueue, ^{
    if (!keepGoing) return;
    if (weAreDoneNow) keepGoing = NO;
}

请注意,enumerateObjectsUsingBlock:enumerateObjectsWithOptions:usingBlock:都支持取消,因为该API的角色不同。枚举方法的调用是 synchronous ,即使枚举块的实际执行可能完全并发,具体取决于选项。

因此,设置*stopFlag=YES会使枚举停止。但是,它并不保证它会在并发情况下立即停止。实际上,枚举可以在停止之前执行一些已经排队的块。

(有人可能会简单地认为返回BOOL以指示枚举是否应该继续是更合理的。这样做会要求同步执行枚举块,即使在并发的情况下也是如此,这样可以检查返回值。这样效率会大大降低。)

答案 1 :(得分:4)

我不认为dispatch_apply支持这个。我可以想到模仿它的最好方法是创建一个__block布尔变量,并在块的开头检查它。如果已经设定,请迅速摆脱困境。你仍然需要在剩下的迭代中运行块,但它会更快。

答案 2 :(得分:1)

你不能break dispatch_apply,因为它不合逻辑。

-enumerateObjectsUsingBlock:中,中断定义明确,因为函数按顺序运行。但是在dispatch_apply中,函数并行运行。这意味着在i=3调用“块”时,i=4调用可能已经启动。如果您break i=3i=4来电是否仍在运行?

@BJ的回答是你能做的最接近的,但总会有一些“溢出”。