DispatchWorkItem не завершает функцию при вызове.cancel()

У меня есть серия HTTP-запросов, выполняемых последовательно с использованием Alamofire в списке функций, вызываемых в основной функции, runTask() что я хочу иметь возможность остановиться. Итак, я настроил runTask() вызов функции в DispatchWorkItem для каждой задачи мне нужно запустить и сохранить рабочий элемент в массиве так:

taskWorkItems.append(DispatchWorkItem { [weak self] in
    concurrentQueue!.async {
        runTask(task: task)
    }
})

Затем я перебираю массив рабочих элементов и вызываю perform() функционировать так:

for workItem in taskWorkItems {
    workItem.perform()
}

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

for workItem in taskWorkItems {
    concurrentQueue!.async {
        workItem.cancel()

        print(workItem.isCancelled)
    }
}

workItem.isCancelled печатает на true; Тем не менее, у меня есть журналы, установленные в функциях, вызываемых runTask() и я до сих пор вижу выполнение функций, хотя workItem.cancel() был вызван и workItem.isCancelled печать true, Что я делаю неправильно и как я могу остановить выполнение своих функций?

2 ответа

TLDR: вызов отмены остановит выполнение задач, если они еще не запущены, но не остановит выполнение того, что уже выполняется.

Так как яблочные документы на этом изношены...

https://medium.com/@yostane/swift-sweet-bits-the-dispatch-framework-ios-10-e34451d59a86

A dispatch work item has a cancel flag. If it is cancelled before running, the dispatch queue won’t execute it and will skip it. If it is cancelled during its execution, the cancel property return True. In that case, we can abort the execution

//create the dispatch work item
var dwi2:DispatchWorkItem?
dwi2 = DispatchWorkItem {
    for i in 1...5 {
        print("\(dwi2?.isCancelled)")
        if (dwi2?.isCancelled)!{
            break
        }
        sleep(1)
        print("DispatchWorkItem 2: \(i)")
    }
}
//submit the work item to the default global queue
DispatchQueue.global().async(execute: dwi2!)

//cancelling the task after 3 seconds
DispatchQueue.global().async{
    sleep(3)
    dwi2?.cancel()
}

Я надеюсь, что мое решение поможет вам.

      var workItem:DispatchWorkItem?
workItem = DispatchWorkItem{
    while (true)
    {
       //Do you code as the loop
       usleep(10_000)
       // This condition is use to check the trigger that your code is done
       // The Loop must be break before you cancel
       if yourFinishedFlagIsDone {
               break
       }
    }
}
// Submit your work items and restore the finish flag
yourFinishedFlagIsDone = false
DispatchQueue.global().async(execute: workItem!)


// Add these lines of code to the event that you want to cancel the Dispatch Item
// Of Course, you need to enable your finish flag
yourFinishedFlagIsDone = true
DispatchQueue.global().async {
     workItem?.cancel()
}

На самом деле это решение является просто методом обхода. Еще одно: вы должны помнить, что вы должны поместить DispatchWorkItem Initialization в начало события, которое вы хотите запустить. Он полностью прекращается, когда вы звонитеworkItem?.cancel()

Другие вопросы по тегам