我现在正在玩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代表DispatchWorkItem.在Objective-C中,对用dispatch_block_testcancel0-dispatch_block_create?language=objc" rel="noreferrer">dispatch_block_create创建的块调用dispatch_block_testcancel8-dispatch_block_cancel" rel="noreferrer">dispatch_block_cancel.然后,您可以测试Swift中的isCancelled(在Objective-C中称为dispatch_block_testcancel)是否取消了.

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); }
    });
}

Swift相关问答推荐

如何将趋势线添加到线性图中?

JSON如何解码空对象

如何获取SCNCamera正在查看的网格点(SCNNode)的局部坐标和局部法线?

编写Swift字符串的属性包装时遇到问题

如何在SWIFT任务中判断当前任务是否已取消(异步/等待)

在扩展中创建通用排序函数

SwiftUI 拖放:如果没有上下文类型,则无法解析对成员‘first’的引用

如何使一个 Reality Composer 场景中的分组对象可拖动?

为什么 SwiftUI 中 ForEach 的这个 Select 不起作用?

是否可以使用 .task 修饰符更新基于两个值的视图

快速递归:函数与闭包

SwiftUI View .tint(_ Color) 方法不起作用

Swift - 订阅视图之外的绑定值

如何在 SwiftUI 中获取视图的位置

将数据附加到 Firebase 实时数据库后,NavigationLink 将我重定向到上一个视图

Swift 读写图片占用大量内存

阻止其他类型的键盘

如何在 Xcode 中的 UITests 下以通用方式访问后退栏按钮项?

如何快速制作虚线?

Swift中字节数组的NSData