如何"突破"dispatch_apply()?

Mic*_*ael 7 cocoa objective-c break grand-central-dispatch objective-c-blocks

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

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

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

GCD有类似的东西吗?

bbu*_*bum 14

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

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

if (is_canceled()) return;
Run Code Online (Sandbox Code Playgroud)

要么:

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

请注意这两个enumerateObjectsUsingBlock:enumerateObjectsWithOptions:usingBlock:两个支持取消,因为API是在不同的作用.即使枚举块的实际执行可能完全并发,取决于选项,对枚举方法的调用也是同步的.

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

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


BJ *_*mer 4

我认为dispatch_apply不支持这一点。我能想到的模仿它的最好方法是创建一个 __block 布尔变量,并在块的开头检查它。如果确定了,就赶紧退出。您仍然需要在其余的迭代中运行该块,但它会更快。