Skip to content

Instantly share code, notes, and snippets.

@KaneCheshire
Last active May 7, 2024 08:13
Show Gist options
  • Save KaneCheshire/b13ad47c2f8cdfef7c6225306a3ba919 to your computer and use it in GitHub Desktop.
Save KaneCheshire/b13ad47c2f8cdfef7c6225306a3ba919 to your computer and use it in GitHub Desktop.
Type-erased Swift Task that cancels itself on deinit
/// A type-erased task that you can store in a collection
/// to allow you to cancel at a later date.
///
/// Upon deinit of the task, the task will be cancelled
/// automatically. Similar to Combine's AnyCancellable.
final class AnyTask {
/// Call this cancellation block to cancel the task manually.
let cancel: () -> Void
/// Checks whether the task is cancelled.
var isCancelled: Bool { isCancelledBlock() }
private let isCancelledBlock: () -> Bool
deinit {
// On deinit, if the task is not cancelled then cancel it
if !isCancelled { cancel() }
}
/// Constructs an AnyTask from the provided Task.
/// The provided task is held strongly until AnyTask is
/// deinitted.
/// - Parameter task: The task to construct with.
init<S, E>(_ task: Task<S, E>) {
cancel = task.cancel
isCancelledBlock = { task.isCancelled }
}
}
extension Task {
var eraseToAnyTask: AnyTask { .init(self) }
}
extension Array where Element == Task<Void, Never> {
var erased: [AnyTask] { map(\.eraseToAnyTask) }
}
@KaneCheshire
Copy link
Author

That’s nice! But means there’s a dependency on Combine which is a system library and not a language library right?

@richardhenry
Copy link

Yes, that’s correct!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment