7

有没有办法模拟块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);
    }
}];

GCD有类似的东西吗?

4

3 回答 3

14

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

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

if (is_canceled()) return;

或者:

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

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

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

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

于 2010-06-23T23:25:45.730 回答
4

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

于 2010-06-23T21:16:55.697 回答
1

你不能breakdispatch_apply因为它不合逻辑。

In -enumerateObjectsUsingBlock:a break 是明确定义的,因为函数是按顺序运行的。但是在dispatch_apply函数中是并行运行的。这意味着在i=3“块”的第 rd 调用时,第i=4th 调用可能已经开始。如果您breaki=3i=4通话还应该运行吗?

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

于 2010-06-23T21:22:36.010 回答