I am currently playing around with Grand Central Dispatch and discovered a class called DispatchWorkItem
. The documentation seems a little incomplete so I am not sure about using it the right way. I created the following snippet and expected something different. I expected that the item will be cancelled after calling cancel
on it. But the iteration continues for some reason. Any ideas what I am doing wrong? The code seems fine for me.
@IBAction func testDispatchItems() { let queue = DispatchQueue.global(attributes:.qosUserInitiated) let item = DispatchWorkItem { [weak self] in for i in 0...10000000 { print(i) self?.heavyWork() } } queue.async(execute: item) queue.after(walltime: .now() + 2) { item.cancel() } }
In your comments, you mention that you were using NSTimer , a.k.a. Timer in Swift. If you want to stop a timer, call timer. invalidate() to stop it. Create a new NSTimer when you want to start it again.
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.
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.
Overview. A DispatchWorkItem encapsulates work to be performed on a dispatch queue or within a dispatch group. You can also use a work item as a DispatchSource event, registration, or cancellation handler.
GCD does not perform preemptive cancelations. So, to stop a work item that has already started, you have to test for cancelations yourself. In Swift, cancel
the DispatchWorkItem
. In Objective-C, call dispatch_block_cancel
on the block you created with dispatch_block_create
. You can then test to see if was canceled or not with isCancelled
in Swift (known as dispatch_block_testcancel
in Objective-C).
func testDispatchItems() { let queue = DispatchQueue.global() var item: DispatchWorkItem? // create work item item = DispatchWorkItem { [weak self] in for i in 0 ... 10_000_000 { if item?.isCancelled ?? true { break } print(i) self?.heavyWork() } item = nil // resolve strong reference cycle of the `DispatchWorkItem` } // start it queue.async(execute: item!) // after five seconds, stop it if it hasn't already queue.asyncAfter(deadline: .now() + 5) { item?.cancel() item = nil } }
Or, in Objective-C:
- (void)testDispatchItem { dispatch_queue_t queue = dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0); static dispatch_block_t block = nil; // either static or property __weak typeof(self) weakSelf = self; block = dispatch_block_create(0, ^{ for (long i = 0; i < 10000000; i++) { if (dispatch_block_testcancel(block)) { break; } NSLog(@"%ld", i); [weakSelf heavyWork]; } block = nil; }); // start it dispatch_async(queue, block); // after five seconds, stop it if it hasn't already dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if (block) { dispatch_block_cancel(block); } }); }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With