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:その API の役割が異なるため、両方とenumerateObjectsWithOptions:usingBlock:両方がキャンセルをサポートしていることに注意してください。オプションによっては、列挙ブロックの実際の実行が完全に同時実行される場合でも、列挙メソッドの呼び出しは同期的です。

したがって、を設定する*stopFlag=YESと、列挙が停止するように指示されます。ただし、同時実行の場合にすぐに停止することを保証するものではありません。実際、列挙は、停止する前に、すでにキューに入れられたブロックをさらにいくつか実行する場合があります。

(列挙を続行するかどうかを示すために戻る方がより合理的であると簡単に考えるかもしれませんBOOL。これを行うには、戻り値をチェックできるように、並列の場合でも、列挙ブロックを同期的に実行する必要がありました。この効率が大幅に悪くなります。)

于 2010-06-23T23:25:45.730 に答える
4

dispatch_apply がこれをサポートしているとは思わない。それを模倣するために私が考えることができる最善の方法は、__block ブール変数を作成し、ブロックの先頭でそれをチェックすることです。設定されている場合は、すぐに救済します。残りの反復でブロックを実行する必要がありますが、その方が高速です。

于 2010-06-23T21:16:55.697 に答える
1

非論理的だから仕方breakない。dispatch_apply

関数が順番に実行されるため、休憩は-enumerateObjectsUsingBlock:明確に定義されています。しかし、関数は並行して実行されます。つまり、「ブロック」の rd 呼び出しで、th 呼び出しが開始された可能性があります。にいる場合、通話は引き続き実行されますか?dispatch_applyi=3i=4breaki=3i=4

@BJの答えはあなたができる最も近いものですが、常に「こぼれ」があります。

于 2010-06-23T21:22:36.010 に答える