Ответ
Задачу можно отменить, вызвав метод 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. Иначе будешь как тот Герасим — работать, блядь, до последнего, хоть все вокруг уже кричат "Да хватит, мудак!".