一个类型擦除的自我取消任务,使使用 Swift 并发更容易

任何任务

一个小型的 Swift 包引入了一种类型,为 Swift 提供了类型擦除,这使得它变得非常容易 在删除泛型后存储在集合中。AnyTaskTask

此外,当它被销毁时,一个会自行取消,让您无需手动取消任何 销毁 S 集合时的挂起任务。如果您愿意,也可以选择退出此行为。AnyTaskAnyTask

最后,如果取消尝试在以下情况下发生取消尝试,还可以将 配置为在调试模式下使断言失败 任务已取消。AnyTask

为什么这很有用

很容易忘记取消 Swift ,即使没有任何东西保留对它的引用,它也会继续运行。 除非您正在创建“即发即弃”任务,否则您可能希望确保在它不再时将其取消 需要(即当拥有类被销毁时)。Task

这意味着您必须手动将一个存储在某个地方,以便以后可以取消它,除非它是 在集合中存储不同类型的 S 非常困难,因为它们可以专门用于不同类型的:TaskTask

let taskA = Task<Bool, Never> { // code to return a Bool }
let taskB = Task<Void, Error> { // code that doesn't return a value but can throw }
let tasks = [taskA, taskB] // This code won't compile

这意味着您需要为每个可能的专用类型使用不同的集合,或者每种类型都需要不同的属性,然后确保记住在 中正确取消它们。TaskTaskdeinit

AnyTask类型擦除 s,这意味着您可以将创建的每个任务存储在单个集合(或集合)中 并且它还会在集合被销毁时自动取消集合中的所有任务,因为当集合被取消时会自行取消:TaskAnyTask

var tasks: [AnyTask] = []
Task<Bool, Never> {}.store(in: &tasks)
Task<Void, Error> {}.store(in: &tasks)

// When `tasks` is destroyed, the `AnyTask`s will automatically cancel the underlying type-erased `Task`s. 

用法

擦除Task

您可以从 Swift 手动创建,但使用便利功能来存储更简单 在 s 的集合中:AnyTaskTaskTaskAnyTask

var tasks: [AnyTask] = []
Task {
    // Async task code
}.store(in: &tasks)

You can also do the same thing with a set of s:AnyTask

var tasks: Set<AnyTask> = []
Task {
    // Async task code
}.store(in: &tasks)

If you want to you can also make a call to erase a task explicitly:

let task: AnyTask = Task {
    // Async task code
}.erased()

Or you can also create an manually from a :AnyTaskTask

let task = Task {
    // Async task code
}
let anyTask = AnyTask(task)

Setting options

Wherever you are able to erase a to you are able to override the default options that the is configured with.TaskAnyTaskAnyTask

Task {}.store(in: &tasks, options: [.assertOnOverCancellation])

Task {}.erased(options: [])

AnyTask(Task {}, options: [])

You can see a full list of available in code.Options

Cancelling a task

You can still manually check if an is cancelled by checking the property:AnyTaskisCancelled

var tasks: [AnyTask] = []
let task: AnyTask = Task {}.store(in: &tasks)
task.isCancelled

You can also explicitly cancel a task by calling :cancel()

var tasks: [AnyTask] = []
let task: AnyTask = Task {}.store(in: &tasks)
task.cancel()

GitHub

点击跳转