如何停止 GCD 中的 DispatchWorkItem?
How to stop a DispatchWorkItem in GCD?
我目前正在玩 Grand Central Dispatch 并发现了一个名为 DispatchWorkItem
的 class。该文档似乎有点不完整,所以我不确定是否以正确的方式使用它。我创建了以下代码片段并期望有所不同。我预计该项目会在调用 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()
}
}
没有调用 "Cancel" 方法将取消 运行 操作的异步 API。在每种情况下,"Cancel" 方法都会做一些事情,以便操作可以查明它是否被取消,并且操作必须不时检查它,然后停止自己做更多的工作。
我不知道有问题的 API,但通常它会像
for i in 0...10000000 {
if (self?.cancelled)
break;
print(i)
self?.heavyWork()
}
GCD 不执行抢先取消。因此,要停止已经开始的工作项,您必须自己测试取消。在 Swift、cancel
the DispatchWorkItem
. In Objective-C, call dispatch_block_cancel
on the block you created with dispatch_block_create
. You can then test to see if was canceled or not with isCancelled
in Swift (known as dispatch_block_testcancel
在 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 ?? true { break }
print(i)
self?.heavyWork()
}
item = nil // resolve strong reference cycle of the `DispatchWorkItem`
}
// start it
queue.async(execute: item!)
// after five seconds, stop it if it hasn't already
queue.asyncAfter(deadline: .now() + 5) {
item?.cancel()
item = nil
}
}
或者,在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); }
});
}
我目前正在玩 Grand Central Dispatch 并发现了一个名为 DispatchWorkItem
的 class。该文档似乎有点不完整,所以我不确定是否以正确的方式使用它。我创建了以下代码片段并期望有所不同。我预计该项目会在调用 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()
}
}
没有调用 "Cancel" 方法将取消 运行 操作的异步 API。在每种情况下,"Cancel" 方法都会做一些事情,以便操作可以查明它是否被取消,并且操作必须不时检查它,然后停止自己做更多的工作。
我不知道有问题的 API,但通常它会像
for i in 0...10000000 {
if (self?.cancelled)
break;
print(i)
self?.heavyWork()
}
GCD 不执行抢先取消。因此,要停止已经开始的工作项,您必须自己测试取消。在 Swift、cancel
the DispatchWorkItem
. In Objective-C, call dispatch_block_cancel
on the block you created with dispatch_block_create
. You can then test to see if was canceled or not with isCancelled
in Swift (known as dispatch_block_testcancel
在 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 ?? true { break }
print(i)
self?.heavyWork()
}
item = nil // resolve strong reference cycle of the `DispatchWorkItem`
}
// start it
queue.async(execute: item!)
// after five seconds, stop it if it hasn't already
queue.asyncAfter(deadline: .now() + 5) {
item?.cancel()
item = nil
}
}
或者,在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); }
});
}