← Назад к вопросам

Как сделать так чтобы UniTask уничтожалась вместе с MonoBehaviour?

1.7 Middle🔥 131 комментариев
#Unity Core

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Управление жизненным циклом UniTask в MonoBehaviour

Чтобы UniTask корректно уничтожалась вместе с MonoBehaviour, необходимо организовать управление ее жизненным циклом с использованием CancellationToken. Это важнейший механизм, предоставляемый UniTask для контроля асинхронных операций. Вот основные подходы, которые я использую в своей практике.

Использование CancellationToken из MonoBehaviour

Самый простой и надежный способ — это использование встроенного CancellationToken, который автоматически отменяется при уничтожении GameObject или компонента:

using Cysharp.Threading.Tasks;
using UnityEngine;
using System.Threading;

public class TaskLifecycleExample : MonoBehaviour
{
    private void Start()
    {
        // Запускаем асинхронную задачу с привязкой к жизненному циклу MonoBehaviour
        RunAsyncTask().Forget();
    }
    
    private async UniTaskVoid RunAsyncTask()
    {
        try
        {
            // Используем GetCancellationTokenOnDestroy() для автоматической отмены
            await UniTask.Delay(1000, cancellationToken: this.GetCancellationTokenOnDestroy());
            Debug.Log("Задача выполнена успешно");
        }
        catch (OperationCanceledException)
        {
            // Задача была отменена при уничтожении GameObject
            Debug.Log("Задача отменена из-за уничтожения объекта");
        }
    }
}

Создание собственного CancellationTokenSource

Для более сложных сценариев, где нужен дополнительный контроль, можно создать собственный CancellationTokenSource:

public class AdvancedTaskManager : MonoBehaviour
{
    private CancellationTokenSource _cancellationTokenSource;
    
    private void Start()
    {
        _cancellationTokenSource = new CancellationTokenSource();
        StartAsyncOperations();
    }
    
    private async UniTaskVoid StartAsyncOperations()
    {
        var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(
            _cancellationTokenSource.Token,
            this.GetCancellationTokenOnDestroy()
        );
        
        await ProcessDataAsync(linkedTokenSource.Token);
    }
    
    private async UniTask ProcessDataAsync(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            // Выполняем работу
            await UniTask.Yield(token);
        }
    }
    
    private void OnDestroy()
    {
        // Явная отмена всех задач при уничтожении
        _cancellationTokenSource?.Cancel();
        _cancellationTokenSource?.Dispose();
    }
}

Ключевые подходы и рекомендации

  1. Всегда используйте CancellationToken — никогда не запускайте UniTask без возможности отмены из MonoBehaviour

  2. Предпочитайте встроенные методы:

    • this.GetCancellationTokenOnDestroy() — основной метод для большинства случаев
    • UniTask.WaitUntilDestroyed(this) — альтернативный подход для ожидания
  3. Правильная обработка исключений:

    private async UniTaskVoid SafeAsyncMethod()
    {
        try
        {
            await SomeOperation(this.GetCancellationTokenOnDestroy());
        }
        catch (OperationCanceledException)
        {
            // Ожидаемое поведение при уничтожении
        }
    }
    
  4. Для фоновых задач используйте PlayerLoopTiming:

    await UniTask.DelayFrame(1, PlayerLoopTiming.Update, this.GetCancellationTokenOnDestroy());
    
  5. Избегайте распространенных ошибок:

    • Не сохраняйте ссылки на незавершенные задачи
    • Всегда проверяйте IsCancellationRequested в длительных циклах
    • Используйте UniTaskVoid вместо UniTask для fire-and-forget задач

Паттерн с использованием UniTaskTracker (для отладки)

public class TrackedAsyncBehaviour : MonoBehaviour
{
    private void Start()
    {
        RunTrackedTask().Forget();
    }
    
    private async UniTaskVoid RunTrackedTask()
    {
        // Добавляем задачу в трекер для отладки
        var task = LongRunningOperation(this.GetCancellationTokenOnDestroy());
        UniTaskTracker.TrackActiveTask(task);
        
        await task;
    }
}

Основное правило, которое я всегда соблюдаю: каждая асинхронная операция в MonoBehaviour должна иметь четко определенную точку отмены, привязанную к жизненному циклу объекта. Это предотвращает утечки памяти, исключения MissingReferenceException и обеспечивает стабильность приложения при горячей перезагрузке сцен или уничтожении объектов. Использование GetCancellationTokenOnDestroy() в 95% случаев является оптимальным решением, так как оно абстрагирует управление жизненным циклом и минимизирует boilerplate код.

Как сделать так чтобы UniTask уничтожалась вместе с MonoBehaviour? | PrepBro