如何在GCD中停止DispatchWorkItem?

Seb*_*ldt 31 grand-central-dispatch cancellation swift dispatchworkitem

我目前正在玩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()
    }
}
Run Code Online (Sandbox Code Playgroud)

Rob*_*Rob 55

GCD不执行抢先取消.因此,要停止已经启动的工作项,您必须自己测试取消.在斯威夫特cancelDispatchWorkItem.在Objective-C中,调用dispatch_block_cancel您创建的块dispatch_block_create.然后,您可以isCancelled在Swift中测试是否已取消(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 { 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()
    }
}
Run Code Online (Sandbox Code Playgroud)

或者,在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); }
    });
}
Run Code Online (Sandbox Code Playgroud)

  • @mattsven - 很好的收获。你是绝对正确的。不幸的是,在实例化`DispatchWorkItem`(解决强引用循环的典型方法)时不能使用`[weak item]` 或`[unowned item]` 模式,所以你必须手动`nil``item`在关闭结束时,就像我在修订后的答案中所做的那样。(但我们可以在我们使用 `asyncAfter` 和 `cancel` 的块中使用典型的 `[weak item]` 模式。) (2认同)