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

Что такое cancel в многозадачности?

1.0 Junior🔥 51 комментариев
#Многопоточность и асинхронность

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

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

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

Что такое cancel в многозадачности в iOS?

В iOS-разработке cancel — это механизм прерывания асинхронных или долго выполняющихся задач, позволяющий корректно остановить операцию, высвободить ресурсы и избежать ненужной работы. Это ключевой аспект управления жизненным циклом задач, особенно в контексте Operation, DispatchWorkItem и URLSessionTask, обеспечивающий отзывчивость приложения и эффективное использование памяти.

Основные случаи применения cancel

  1. Operation и OperationQueue
    Классы Operation предоставляют встроенную поддержку отмены через свойство isCancelled. При вызове cancel() флаг isCancelled устанавливается в true, и задача должна периодически проверять его, чтобы досрочно завершить выполнение.

    class LongRunningOperation: Operation {
        override func main() {
            guard !isCancelled else { return }
            
            for i in 0..<100 {
                if isCancelled {
                    print("Операция отменена")
                    return
                }
                // Имитация работы
                Thread.sleep(forTimeInterval: 0.1)
            }
        }
    }
    
    let operation = LongRunningOperation()
    let queue = OperationQueue()
    queue.addOperation(operation)
    // Отмена через 2 секунды
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        operation.cancel()
    }
    
  2. DispatchWorkItem
    DispatchWorkItem позволяет отменить задачу до её выполнения в очереди DispatchQueue. Если задача уже началась, отмена не прервёт её выполнение, но может быть проверена через workItem.isCancelled.

    let workItem = DispatchWorkItem {
        for i in 1...5 {
            if Thread.isCancelled {
                return
            }
            print("Шаг \(i)")
            sleep(1)
        }
    }
    
    DispatchQueue.global().async(execute: workItem)
    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
        workItem.cancel() // Остановит, если задача ещё не началась
    }
    
  3. URLSessionTask
    При сетевых запросах отмена через task.cancel() прекращает передачу данных и освобождает сетевое соединение. Это полезно при уходе с экрана или обновлении данных.

    var task: URLSessionDataTask?
    
    func startRequest() {
        let url = URL(string: "https://api.example.com/data")!
        task = URLSession.shared.dataTask(with: url) { data, response, error in
            if let error = error as? URLError, error.code == .cancelled {
                print("Запрос отменён")
                return
            }
            // Обработка ответа
        }
        task?.resume()
    }
    
    func cancelRequest() {
        task?.cancel()
        task = nil
    }
    

Важные аспекты отмены

  • Кооперативная отмена: В большинстве случаев cancel() лишь устанавливает флаг, а задача сама должна проверять его и завершаться. Это требует аккуратной реализации в коде.
  • Освобождение ресурсов: При отмене сетевых запросов или операций с файлами важно закрывать соединения и освобождать память.
  • Обработка ошибок: После отмены часто возникают специфические ошибки (например, URLError.cancelled), которые нужно корректно обрабатывать.
  • Отмена в Combine: Во фреймворке Combine отмена осуществляется через AnyCancellable и метод cancel() на подписках, что автоматически освобождает ресурсы.

Пример комплексного использования

class ViewModel {
    private var operations: [Operation] = []
    private var cancellables = Set<AnyCancellable>()
    
    func startTasks() {
        let operation = BlockOperation {
            // Долгая задача
        }
        operations.append(operation)
        OperationQueue().addOperation(operation)
        
        // Combine publisher
        URLSession.shared.dataTaskPublisher(for: someURL)
            .sink(receiveCompletion: { _ in },
                  receiveValue: { _ in })
            .store(in: &cancellables)
    }
    
    func cancelAll() {
        operations.forEach { $0.cancel() }
        cancellables.forEach { $0.cancel() }
    }
}

cancel — это не просто остановка задачи, а часть архитектурного подхода к управлению асинхронностью. Правильное использование:

  • Улучшает пользовательский опыт (быстрый отклик на действия).
  • Снижает потребление батареи и сетевого трафика.
  • Предотвращает утечки памяти и конфликты в данных.
  • Особенно важно в SwiftUI и Combine, где жизненный цикл представлений часто требует автоматической отмены подписок.

Игнорирование отмены может привести к "зависанию" интерфейса, накоплению фоновых задач и в конечном итоге — к крашу приложения. Поэтому реализация поддержки cancel должна быть стандартной практикой для всех долгоиграющих операций.

Что такое cancel в многозадачности? | PrepBro