Ответ
GCD не предоставляет прямого механизма отмены уже запущенной задачи, но есть несколько обходных решений:
1. DispatchWorkItem (отмена до выполнения)
let workItem = DispatchWorkItem {
print("Эта задача может быть отменена")
}
// Запланировать выполнение
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5, execute: workItem)
// Отменить до начала выполнения
workItem.cancel()
2. Флаг отмены для выполняющихся задач
class CancellableTask {
private var isCancelled = false
private let queue = DispatchQueue(label: "com.example.task", attributes: .concurrent)
func start() {
queue.async { [weak self] in
guard let self = self else { return }
for i in 1...100 {
// Периодическая проверка флага
if self.isCancelled {
print("Задача отменена на шаге (i)")
return
}
// Полезная работа
Thread.sleep(forTimeInterval: 0.1)
}
}
}
func cancel() {
queue.async(flags: .barrier) {
self.isCancelled = true
}
}
}
3. OperationQueue (предпочтительный способ)
let operationQueue = OperationQueue()
let operation = BlockOperation {
// Длительная операция
}
operationQueue.addOperation(operation)
// Отмена операции
operation.cancel()
Рекомендации:
- Для сложных сценариев используйте
OperationQueueс поддержкой зависимостей и отмены - В современных Swift проектах предпочитайте
async/awaitсTaskиTask.checkCancellation() - Всегда реализуйте периодическую проверку флагов отмены в длительных операциях
Ответ 18+ 🔞
А, слушай, вот это реально пиздец, как же бесит, когда тебе надо остановить какую-то хуйню, а она уже поехала! GCD, блядь, такая штука: запустил — и всё, поезд ушёл. Прямого рычага «СТОП, НАХУЙ!» там нет. Но русские, как всегда, нашли, где схитрить.
1. DispatchWorkItem (Отмена, пока не начал ебашить) Представь, ты поставил будильник, а потом передумал. Вот это оно.
let workItem = DispatchWorkItem {
print("Эта задача может быть отменена")
}
// Запланировать выполнение
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5, execute: workItem)
// Отменить до начала выполнения
workItem.cancel()
Работает, только если задача ещё в очереди болтается, как сопля. Как только исполнитель схватил её — всё, пиши пропало, отменить не выйдет. Чистая лотерея, ёпта.
2. Самопальный флаг отмены (Для тех, кто уже в процессе) Это когда ты кричишь «СТОЙ!», а работяга периодически оглядывается, не ты ли это орёшь. Грязно, но работает.
class CancellableTask {
private var isCancelled = false
private let queue = DispatchQueue(label: "com.example.task", attributes: .concurrent)
func start() {
queue.async { [weak self] in
guard let self = self else { return }
for i in 1...100 {
// Периодическая проверка флага
if self.isCancelled {
print("Задача отменена на шаге (i)")
return
}
// Полезная работа
Thread.sleep(forTimeInterval: 0.1)
}
}
}
func cancel() {
queue.async(flags: .barrier) {
self.isCancelled = true
}
}
}
Суть в том, что твоя длительная операция должна быть не упоротой и иногда спрашивать: «А не пора ли мне нахуй?». Если флаг isCancelled поднят — делаем ноги. Барьер тут, чтобы не было гонок, а то получишь пиздец, а не отмену.
3. OperationQueue (Царь-пушка, предпочтительный способ) Вот это уже серьёзно, блядь. Тут уже есть встроенная, нормальная отмена.
let operationQueue = OperationQueue()
let operation = BlockOperation {
// Длительная операция
}
operationQueue.addOperation(operation)
// Отмена операции
operation.cancel()
Операция сама, внутри себя, должна уважительно проверять свойство isCancelled и вовремя сваливать. Если не проверяет — то это просто упырь несчастный, а не операция.
Рекомендации на полях:
- Для сложной хуйни с зависимостями и очередями — только
OperationQueue, без вариантов. Там и отмена, и приоритеты, и жди друг друга. - Если ты уже в современном Swift и используешь
async/await, то там своя магия:TaskиTask.checkCancellation(). Это уже цивилизация, а не наши костыли. - Запомни раз и нахуй: любая длительная операция ДОЛЖНА быть вежливой и периодически проверять, не послали ли её. Иначе это не операция, а говно вентилятором размазанное.