In Swift’s concurrency model, cancellation is cooperative. To be a good concurrency citizen, code must periodically check if the current task has been cancelled, and react accordingly.
By convention, functions should react to cancellation by throwing a
CancellationError. But this convention isn’t enforced, so callers must be aware that cancellation can manifest itself in other forms. Here are some other ways how functions might respond to cancellation:
Throw a different error. For example, the async networking APIs in Foundation, such as
URLSession.data(from: URL), throw a
URLErrorwith the code
URLError.Code.cancelledon cancellation. It’d be nice if
URLSessiontranslated this error to
CancellationError, but it doesn’t.
Return a partial result. A function that has completed part of its work when cancellation occurs may choose to return a partial result rather than throwing the work away and aborting. In fact, this may be the best choice for a non-throwing function. But note that this behavior can be extremely surprising to callers, so be sure to document it clearly.
Do nothing. Functions are supposed to react promptly to cancellation, but callers must assume the worst. Even if cancelled, a function might run to completion and finish normally. Or it might eventually respond to cancellation by aborting, but not promptly because it doesn’t perform its cancellation checks often enough.
So as the caller of a function, you can’t really rely on specific cancellation behavior unless you know how the callee is implemented. Code that wants to know if its task has been cancelled should itself call
Task.isCancelled, rather than counting on catching a
CancellationError from a callee.