Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DispatchWorkItem not terminating function when .cancel() is called

I have a series of HTTP requests made sequentially using Alamofire in a list of functions called in a main function, runTask() that I want to have the ability to stop. So, I set up the runTask() function call in a DispatchWorkItem for each of the task I need to run and store the work item in an array like so:

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

Then, I iterate of the array of work items and call the perform() function like so:

for workItem in taskWorkItems {
    workItem.perform()
}

Finally, I have a button in my app that I want to cancel the work items when tapped, and I have the following code to make that happen:

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

        print(workItem.isCancelled)
    }
}

workItem.isCancelled prints to true; however, I have logs set up in the functions called by runTask() and I still see the functions executing even though workItem.cancel() was called and workItem.isCancelled prints true. What am I doing wrong and how can I stop the execution of my functions?

like image 984
ch1maera Avatar asked Oct 03 '18 20:10

ch1maera


People also ask

How do I cancel a dispatch work item?

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.

How do I cancel a GCD task?

You can't pause / cancel when using a GCD queue. If you need that functionality (and in a lot of general cases even if you don't) you should be using the higher level API - NSOperationQueue .

How do I cancel Dispatchqueue?

You don't stop the queue. Instead, when the task that you dispatched starts executing, it needs to check its context and do the right thing (often: nothing) if the context has changed.


Video Answer


1 Answers

TLDR: calling cancel will stop tasks from executing if they have yet to be run, but won't halt something that's already executing.

Since the apple docs on this are threadbare...

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()
}
like image 71
Eric H Avatar answered Oct 09 '22 14:10

Eric H