私は現在Grand Central Dispatchで遊んでいて、DispatchWorkItem
というクラスを発見しました。ドキュメントは少し不完全に見えるので、正しい方法で使用するかどうかはわかりません。次のスニペットを作成し、別の何かを期待していました。 cancel
を呼び出した後、アイテムがキャンセルされることを期待していました。しかし、何らかの理由で反復が継続します。私が間違っていることは何ですか?コードは私にとっては問題ないようです。
@IBAction func testDispatchItems() {
let queue = DispatchQueue.global(attributes:.qosUserInitiated)
let item = DispatchWorkItem { [weak self] in
for i in 0...10000000 {
print(i)
self?.heavyWork()
}
}
queue.async(execute: item)
queue.after(walltime: .now() + 2) {
item.cancel()
}
}
GCDはプリエンプティブキャンセルを実行しません。そのため、すでに開始されているワークアイテムを停止するには、キャンセルを自分でテストする必要があります。 Swiftでは、 cancel
the DispatchWorkItem
。 Objective-Cでは、 _dispatch_block_cancel
_ で作成したブロックで _dispatch_block_create
_ を呼び出します。 isCancelled
in Swift(として知られている _dispatch_block_testcancel
_ in Objective-C)。
_func testDispatchItems() {
let queue = DispatchQueue.global()
var item: DispatchWorkItem!
// create work item
item = DispatchWorkItem { [weak self] in
for i in 0 ... 10_000_000 {
if item.isCancelled { break }
print(i)
self?.heavyWork()
}
item = nil // resolve strong reference cycle
}
// start it
queue.async(execute: item)
// after five seconds, stop it if it hasn't already
queue.asyncAfter(deadline: .now() + 5) { [weak item] in
item?.cancel()
}
}
_
または、Objective-Cでは:
_- (void)testDispatchItem {
dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0);
static dispatch_block_t block = nil; // either static or property
__weak typeof(self) weakSelf = self;
block = dispatch_block_create(0, ^{
for (long i = 0; i < 10000000; i++) {
if (dispatch_block_testcancel(block)) { break; }
NSLog(@"%ld", i);
[weakSelf heavyWork];
}
block = nil;
});
// start it
dispatch_async(queue, block);
// after five seconds, stop it if it hasn't already
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (block) { dispatch_block_cancel(block); }
});
}
_
「キャンセル」メソッドを呼び出すと実行中の操作がキャンセルされる非同期APIはありません。いずれの場合も、「キャンセル」メソッドは何かを実行するため、操作はキャンセルされたかどうかを確認できます。操作は時々これを確認し、それ以上の作業を停止する必要があります。
問題のAPIはわかりませんが、通常は次のようになります
for i in 0...10000000 {
if (self?.cancelled)
break;
print(i)
self?.heavyWork()
}