Как отменить выполнение задачи (NSOperation) в Swift?

Ответ

Задачу можно отменить, вызвав метод cancel() у экземпляра NSOperation или Operation. Однако отмена является кооперативной — операция не прекращается мгновенно, а лишь устанавливает свойство isCancelled в true. Код внутри операции должен периодически проверять это свойство и корректно завершать свою работу.

Правильная реализация отмены в кастомной операции:

class MyLongOperation: Operation {
    override func main() {
        // 1. Проверить отмену перед началом работы
        guard !isCancelled else { return }

        // 2. Выполнять длительную работу с периодическими проверками
        for i in 1...1000 {
            if isCancelled { // 3. Проверка в цикле
                // Очистка ресурсов при необходимости
                return
            }
            // ... выполнение шага работы ...
            print("Step (i)")
        }
    }
}

// Использование
let operationQueue = OperationQueue()
let operation = MyLongOperation()
operationQueue.addOperation(operation)

// Отмена операции через 2 секунды
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    operation.cancel() // Устанавливает isCancelled = true
}

Важные моменты:

  • После вызова cancel() операция остается в очереди до момента, когда ее main() метод завершится.
  • Свойства isFinished и isExecuting меняются системой только после реального завершения main().
  • Для отмены всех операций в очереди используйте operationQueue.cancelAllOperations().
  • Отмененные зависимости (addDependency) не препятствуют запуску зависящей операции, если она готова к выполнению.

Ответ 18+ 🔞

А, слушай, вот эта вся хуйня с отменой операций в NSOperation — это ж классика, блядь! Ну то есть ты такой думаешь: "О, отменил и всё, пиздец, конец истории!" А нихуя подобного, ёпта!

Это ж не как того мудака с кнопкой — нажал и всё, блядь, нахуй, вырубилось. Тут система такая, подлая, сука. Ты кричишь cancel(), а она тебе тихонечко так, по-пионерски: "Так, дружочек, я флажочек твой isCancelled подняла, а дальше сам разбирайся, мудила".

Вот смотри, как правильно эту пантомиму организовать, чтобы не остаться с операцией, которая уже отменена, но всё ещё ебёт твой процессор, как последняя шлюха:

class MyLongOperation: Operation {
    override func main() {
        // 1. Сразу на входе проверь — а не послали ли нас уже нахуй?
        guard !isCancelled else { return } // Всё, свободен, Чикатило!

        // 2. Ну допустим, не послали. Начинаем свою муторную работу.
        for i in 1...1000 {
            // 3. Вот тут самый сок, блядь! После каждого чиха спрашивай:
            // "А меня ещё не отменили, сука?"
            if isCancelled {
                // Да, отменили. Подтираемся и уходим.
                return
            }
            // ... а тут делаем вид, что мы полезные ...
            print("Step (i)")
        }
    }
}

Используется это, понятное дело, так:

let operationQueue = OperationQueue()
let operation = MyLongOperation()
operationQueue.addOperation(operation)

// А через две секунды передумываем:
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
    operation.cancel() // Пшикнули флажком! isCancelled = true
}

И вот тут, сука, главный подвох, который всех наебывает: после твоего cancel() операция-то не испаряется, блядь! Она так и будет висеть в этой очереди, как сраный призрак, пока её main() метод сам не додумается завершиться. Свойства isFinished и isExecuting — это священные коровы, их меняет только система, когда всё реально кончилось.

Хочешь по-быстрому всё похерить? Пожалуйста: operationQueue.cancelAllOperations(). Вжух — и все флажки isCancelled торчком, как удивлённые члены.

И ещё одна хитрая жопа: зависимости. Допустим, операция Б ждёт операцию А. Ты отменил А. Так вот, Б-то не будет ждать вечно, ёпта! Если Б уже готова бежать, а А отменена — Б побежит, нахуй. Отмена зависимости — это не барьер, это просто совет, мол, "та операция уже ни хуя не сделает, можешь не ждать".

Короче, вся суть в том, что отмена — это не приказ "немедленно прекратить!", а вежливая просьба "пожалуйста, прекрати, когда сможешь". А сможешь ты только если сам, в своей операции, не забыл поставить эти чёртовы проверки isCancelled. Иначе будешь как тот Герасим — работать, блядь, до последнего, хоть все вокруг уже кричат "Да хватит, мудак!".