Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cancel a specific DispatchQueue.main.asyncAfter event? [duplicate]

I have this block of code:

    DispatchQueue.main.asyncAfter(deadline: .now() + (delay * Double(isDelayAccounted.hashValue)) + extraDelay) {
        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)   
    }

Now, I want to be able to stop this thread from executing. How can I stop it from being executed? For instance, after 3 seconds, I decide I don't want that to execute anymore so I want to stop it.

like image 279
Pablo Avatar asked Jun 19 '17 14:06

Pablo


People also ask

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.

How to run code after some time in swift?

Execute Code After Delay Using asyncAfter() Sometimes, you might hit the requirement to perform some code execution after a delay, and you can do this by using Swift GCD (Grand Central Dispatch) system to execute some code after a set delay.

How to call method after delay in swift?

Here we are creating one function functionOne, where first we are declaring delay time which is 3 Seconds. Then we are using asyncAfter where we are giving the delay time as a parameter and asking to execute hello() function after 3 seconds.


2 Answers

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()
like image 140
Dávid Pásztor Avatar answered Oct 03 '22 10:10

Dávid Pásztor


You could use an one-shot DispatchSourceTimer rather than asyncAfter

var oneShot : DispatchSourceTimer!

 oneShot = DispatchSource.makeTimerSource(queue: DispatchQueue.main)
 oneShot.scheduleOneshot(deadline: .now() + (delay * Double(isDelayAccounted.hashValue)) + extraDelay))
 oneShot.setEventHandler {
     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)   
 }
 oneShot.setCancelHandler {
     // do something after cancellation
 }

 oneShot.resume()

and cancel the execution with

oneShot?.cancel()
oneShot = nil
like image 37
vadian Avatar answered Oct 03 '22 11:10

vadian