Stop Dispatch_After

Prevent dispatch_after() background task from being executed

Why even use GCD? You could just use an NSTimer and invalidate it when your app returns to the foregound.

Stop a DispatchQueue that is running on the main thread

You can use DispatchWorkItems. They can be scheduled on DispatchQueues and cancelled before their execution.

let work = DispatchWorkItem(block: {
self.isShootingOnHold = false
self.shoot()
self.shootingEngine = Timer.scheduledTimer(timeInterval: (Double(60)/Double(self.ratePerMinute)), target: self, selector: #selector(ShootingEnemy.shoot), userInfo: nil, repeats: true)
})
DispatchQueue.main.asyncAfter(deadline: .now() + (delay * Double(isDelayAccounted.hashValue)) + extraDelay, execute: work)
work.cancel()

How to stop a DispatchWorkItem in GCD?

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); }
});
}

Pass DispatchTime as an argument in DispatchAfter

This is what you want in Swift 3+:

let seconds = 2.0
// dispatchTime 2 seconds from now:
let dispatchTime: DispatchTime = DispatchTime.now() + seconds
DispatchQueue.main.asyncAfter(deadline: dispatchTime) {
// code to be executed
}


Related Topics



Leave a reply



Submit