Stop a DispatchQueue that is running on the main thread
You can use DispatchWorkItem
s. They can be scheduled on DispatchQueue
s 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()
Why does Dispatchqueue.main.async still excute the block in main thread?
You said:
I know when we use
.async
to execute the task we won't block the main thread.
Yes, we often dispatch asynchronously to a background queue to avoid blocking the main thread. But, more accurately, we technically use async
to avoid blocking the current thread. Sure, if you’re on the main thread, that means we’re not blocking the main thread. But if you’re currently running on a background thread, then async
just keeps you from blocking that current background thread.
... but why we use
DispatchQueue.main.async
?
This is commonly used when you’re already on a background thread, but have something (like a UI update) that must be run on the main thread. Then you’d dispatch that UI update from the background thread back to the main queue. And we’d generally do this asynchronously because there’s no point in having that background thread wait for the UI update.
E.g.
DispatchQueue.global().async {
// do something computationally intensive here ...
// ... but when you want to update the UI with the result, you’d dispatch that back to the main queue
DispatchQueue.main.async {
self.label.text = ...
}
}
Or you’d use the same pattern when using URLSession
(or anything that runs on a background thread). We’d use DispatchQueue.main.async
if we’re currently on some background thread, but need to perform UI updates, which must always happen on the main thread. So we’d dispatch those UI updates back to the main queue.
That’s why we use DispatchQueue.main.async
. That having been said, while there is rarely any utility to it, you technically can dispatch asynchronously from the main thread back to itself, like you have in your question. All that will happen is that the dispatched code will be added to the end of the main queue, but won’t run until you finish whatever you were previously doing on the main thread.
For example, imagine that the following is run on the main thread
print("a")
DispatchQueue.main.async {
print("b")
}
print("c")
You’ll see “a”, the print("b")
will be queued (but not run yet), you’ll then carry on the main thread and will see “c”. Then when you eventually yield back to the app’s run loop, only then will the main thread be freed so that print("b")
can be performed. So you’ll see “a” and “c”, first, and then “b”!
how to stop a dispatchQueue in swift
I'm not sure if there are best practices here, but I would consider doing what you are doing with a Timer rather than the DispatchQueue.
class GifClass: UIViewController {
@IBOutlet weak var gifImage: UIImageView!
@IBOutlet weak var skipButton: UIButton!
var timer = Timer()
override func viewDidLoad() {
super.viewDidLoad()
gifImage.loadGif(name: "promed")
timer = Timer.scheduledTimer(timeInterval: 11, target: self, selector: #selector(timerAction), userInfo: nil, repeats: false)
}
@objc func timerAction() {
performSegue(withIdentifier: "introLogin", sender: self)
}
@IBAction func skip(_ sender: Any) {
timer.invalidate()
performSegue(withIdentifier: "introLogin", sender: self)
}
}
How to stop execution of a running background thread from main thread on swift while using DispatchQueue
I think the best solution is to execute DispatchWorkItem
in async
:
DispatchWorkItem encapsulates work that can be performed. A work item can be dispatched onto a DispatchQueue and within a DispatchGroup
so at the end your code might be:
let workItem = DispatchWorkItem {
//.... writing stuff in background ....
DispatchQueue.main.async {
//.... done writing stuff, updating ui ....
}
}
DispatchQueue.global().async(execute: workItem)
when you need to stop the execution just call .cancel()
:
//.... but, if stuff goes wrong ....
DispatchQueue.main.async {
workItem.cancel()
}
Swift Cancel DispatchQueue Process
There is no way to stop or "kill" a DispatchWorkItem
or NSOperation
from outside. There is a cancel()
method, but that merely sets the isCancelled
property of the item or operation to true. This does not stop the execution of the item itself. Ans since recv
is blocking, there is no way to check the isCancelled
flag during execution. This means the answer posted by Vadian unfortunately wouldn't do anything.
According to the Apple docs on NSOperation.cancel
:
This method does not force your operation code to stop.
The same goes for NSOperationQueue.cancelAllOperations
:
Canceling the operations does not automatically remove them from the queue or stop those that are currently executing.
You might think it is possible to drop down to using a raw NSThread
. However, the same principle applies hier. You cannot deterministically kill a thread from the outside.
Possible solution: timeout
The best solution I can think of is to use the timeout feature of the socket. I don't know where UDPServer
comes from, but perhaps it has a built in timeout.
Possible solution: Poor man's timeout (send packet to localhost)
Another option you can try is to send some UDP packets to yourself after a certain time has elapsed. This way, recv
will receive some data, and execution will continue. This could possibly be used as a "poor man's timeout".
Related Topics
Type Conversion When Using Protocol in Swift
Make Code With Firebase Asynchronous
Try, Try! & Try? What's the Difference, and When to Use Each
How to Silence a Warning in Swift
Swap Rootviewcontroller With Animation
Swift Xcode Index Freezing or Slow
How to Document the Parameters of a Function'S Closure Parameter in Swift 3
How to Access Program Arguments in Swift
Get Button Pressed Id on Swift Via Sender
Programmatically Screenshot | Swift 3, Macos
Is Swiftui Backwards-Compatible With iOS 12.X and Older
Swiftui: Pop to Root View When Selected Tab Is Tapped Again
Whats the Swift Animate Withduration Syntax
How to Check Two Instances Are the Same Class/Type in Swift
Swift - Increment Label With Stepper in Tableview Cell
How to Use Array.Filter to Filter a Class Object Based on a Property