What happens if a Task is not canceled?

I read everywhere that I can use a Task {....} inside a UIViewController to perform async operations in a concurrent @MainActor environment and the caveat was that the Task must be canceled manually.
My app works fine without cancelling the Task after I fetch a simple data from a REST API and update a table view so I was wondering what happens if I don't cancel the task?

class BalanceViewController: UIViewController {
var myTask : Task<Void, Never>?
.....
override func viewDidLoad() {
super.viewDidLoad()
myTask = Task {
            balances = await getBalances() //async network call
            myTable.reloadData()
        }
}

Generally speaking, you don't have absolute control over the lifetime of a Task. A task will exist in memory, along with whatever values it's retaining at the current moment, until it completes (no code left to run or await.)

In your example above, you'll end up keeping self (implicitly), myTable, and balances in memory until getBalances() and reloadData() finish, even if you dismiss the view controller.

Something else to keep in mind: cancellation is cooperative, which means when you cancel a Task you're really just setting a boolean flag — it's up to your Task's code to check and respond to that cancellation. So in your example above, even if you cancelled the Task it would continue to run, unless getBalances or reloadData respond to task cancellation and throw an exception or error. You can still check Task.isCancelled or use withTaskCancellationHandler though to handle cancellation yourself.

5 Likes

Thank you @mattcurtis .
I thought the task will never release the resources unless I cancel it at some point.

It seems to me that task cancelation is not really needed in simple scenarios like the one described here? Or am I missing something?

That's ultimately up to you to decide. If all you want to be sure of is that eventually resources will be released, in most cases (unless you're awaiting something that never returns) the answer is yes. But rather or not you need to explicitly cancel a task is probably going to depend on the work it's doing, how expensive it might be, whether or not that work has side-affects, etc.

2 Likes

If your question is just "do I have to cancel a task in order to clean up after it?", the answer is no, you do not. Cancellation is no more than a semantic tool for communicating to a task that its work is no longer required. Some operations will respond to cancellation by cutting their work short; for example, Task.sleep will return immediately (by throwing).

The documentation is just saying that structured sub-tasks are automatically cancelled when the parent parent task is cancelled, so if you want this automatic cancellation behavior with unstructured tasks, you'll have to do it yourself.

5 Likes

Thank you all for the clarifications

For a more detailed explanation about top level task cancellation and what happens under different circumstances, here is a great article by John Sundell

1 Like