После отмены родительской задачи автоматически отменяется созданная внутри неё Task.detached?
Нет. Task.detached не является дочерней задачей родительской задачи, поэтому автоматически не наследует её состояние отмены. Отмену нужно явно передать через дескриптор задачи или другой согласованный механизм, причём отмена в Swift кооперативная: задача должна проверять состояние отмены и завершаться самостоятельно.
Структурированная конкурентность появилась в Swift, чтобы связывать время жизни дочерних задач с областью выполнения родителя и автоматически распространять контекст, включая отмену. Такой подход уменьшает риск утечек задач и фоновой работы, продолжающейся после завершения операции-владельца.
Task.detached предназначена для намеренного выхода из этой структуры. Она позволяет запустить независимую задачу без наследования контекста родителя, когда такая независимость действительно нужна.
Если родительская задача обслуживает экран, сетевой запрос или временную операцию, её отмена обычно означает, что связанная работа больше не нужна. Использование Task.detached в таком месте может оставить фоновую задачу выполняться после ухода пользователя со страницы.
Это приводит к лишней нагрузке, попыткам обновить уже неактуальное состояние и неожиданным побочным эффектам. Особенно опасно ошибочно считать сам факт вызова await или хранения дескриптора достаточным для установления родительско-дочерней связи.
Task.detached создаёт неструктурированную задачу. Она не получает автоматически отмену родителя, его task-local значения, приоритет и изоляцию текущего актора. Для управления такой задачей вызывающий код должен сохранить возвращённый объект Task и при необходимости вызвать у него cancel().
Вызов cancel() не прерывает выполнение принудительно. Он только устанавливает флаг отмены у целевой задачи; код задачи должен регулярно обращаться к Task.isCancelled, вызывать Task.checkCancellation() или ожидать отменяемые операции.
Минимальная схема явного управления выглядит так:
Здесь worker.cancel() только помечает задачу отменённой. Цикл завершится потому, что проверяет Task.isCancelled; без такой проверки detached-задача могла бы продолжить работу.
Если работа логически принадлежит родителю, предпочтительнее обычная Task в подходящем структурированном контексте или дочерняя задача через async let либо TaskGroup. Task.detached оправдана для действительно независимого процесса, например отдельного фонового владельца очереди, но тогда его жизненный цикл нужно проектировать отдельно.
Важно отличать отмену самой detached-задачи от отмены операции, которую она выполняет. Даже при явном вызове cancel() внешняя библиотека или блокирующая системная функция может не поддерживать отмену, поэтому задача не обязательно завершится немедленно.
Экран запускает фоновую подготовку большого набора данных через Task.detached, а пользователь быстро закрывает экран. Если дескриптор не сохранён, экран не может передать задаче отмену; вычисление продолжится, хотя результат уже никому не нужен.
Рассматривались два варианта. Обычная дочерняя задача автоматически связывает жизненный цикл с родителем, но не подходит, если вычисление должно пережить закрытие экрана. Detached-задача даёт независимость, однако требует отдельного владельца, явного метода отмены и безопасного способа публикации результата.
Выбран вариант с объектом-координатором, который хранит дескриптор detached-задачи, отменяет его при завершении операции и проверяет актуальность результата перед публикацией. Это сохраняет независимость вычисления, но делает её жизненный цикл явным и предотвращает публикацию устаревших данных.
await на detached-задачу отмену родителя?Нет. await лишь ожидает результат задачи и не превращает её в дочернюю. Если родитель отменён, detached-задача сама по себе не получает отмену; связь нужно реализовать явно.
cancel() для немедленной остановки detached-задачи?Нет. Отмена кооперативная и меняет состояние задачи, но не прерывает произвольный синхронный код. Задача должна проверять отмену, использовать Task.checkCancellation() или вызывать API, поддерживающий отмену.
Объект может жить до завершения detached-задачи, потому что задача удерживает захваченную ссылку. При долгой или зависшей работе это задержит деинициализацию владельца; поэтому следует продумать слабый захват, явную отмену и безопасное завершение операции, если сильная ссылка не нужна.