How to notify a queue in Swift (GCD)
Try this change:
self.geoFire?.getLocationForKey(wave.waveID, withCallback: { (location, error) in
defer { dispatchGroup.leave() }
guard let location = location else { return }
if error == nil {
if location.distance(from: currentLocation) < Constants.distance {
print("Wave", wave.waveID, "is in range")
waves.append(wave)
} else {
print("Wave", wave.waveID, "is out of range")
}
} else {
print(error?.localizedDescription ?? "")
}
})
As noted in matt's comment defer
is a good tool to do something always when leaving.
This is another issue, but updating an Array from multiple thread simultaneously would cause some problems. It rarely happens, so it can be a hard-to-fix bug.
I'm not sure if GeoFire
calls its callback in the main thread or not, but if not, you should better enclose all the callback code in DispatchQueue.main.async {...}
.
Swift: Simple DispatchQueue does not run & notify correctly
You should put the group.leave()
statement in the dispatchQueue.async
block as well, otherwise it will be executed synchronously before the async block would finish execution.
@objc func buttonTapped(){
let group = DispatchGroup()
let dispatchQueue = DispatchQueue.global(qos: .default)
for i in 1...4 {
group.enter()
dispatchQueue.async {
print(" \(i)")
group.leave()
}
}
for i in 1...4 {
group.enter()
dispatchQueue.async {
print("❌ \(i)")
group.leave()
}
}
group.notify(queue: DispatchQueue.main) {
print("jobs done by group")
}
}
Grand Central Dispatch-Check for Task Completion
You just need to place it in a main
queue after your code:
let globalQueue = DispatchQueue.global()
globalQueue.async {
// Your code here
DispatchQueue.main.async {
self.treeview.reloadData()
}
}
Dispatch Group not notifying?
It's a good practice to make leave top of callback
guard error == nil else { print("get heart rate error"); dispatchGroup.leave() return ; }
guard let unwrappedResults = results as? [HKQuantitySample] else { print("get heart rate error"); dispatchGroup.leave(); return}
let heartRatesAsDouble = unwrappedResults.map {$0.quantity.doubleValue(for: heartRateUnit)}
guard let max = heartRatesAsDouble.max() else { dispatchGroup.leave(); return }
let maxAsCustomHistoricalSample = CustomHistoricalSample(value: max, date: workout.startDate)
heartRateMaxArrayAsCustomHistoricalSample.append(maxAsCustomHistoricalSample)
let average = heartRatesAsDouble.average
let averageAsCustomHistoricalSample = CustomHistoricalSample(value: average, date: workout.startDate)
dispatchGroup.leave()
heartRateAvgArrayAsCustomHistoricalSample.append(averageAsCustomHistoricalSample)
Generic Grand Central Dispatch
let item = DispatchWorkItem{
// async stuff happening like downloading an image
// print success if image downloads
}
OK, defines it, but nothing runs yet.
queue1.sync(execute: item)
Execute item
and kick off its async events. Immediately return after that. Nothing here says "wait for those unrelated asynchronous events to complete." The system doesn't even have a way to know that there are additional async calls inside of functions you call. How would it know whether object.doit()
includes async calls or not (and whether those are async calls you meant to wait for)? It just knows when item
returns, continue.
This is what group1
is supposed to be used for (you don't seem to use it for anything). Somewhere down inside these "async stuff happening" you're supposed to tell the system that it finished by leaving the group. (I have no idea what group2
is for. It's never used either.)
item.notify(queue1, execute: {
print("did this finish?")
})
item
already finished. We know it has to have finished already, because it was run with sync
, and that doesn't return until its item has. So this block will be immediately scheduled on queue1
.
queue2.sync {
print("queue2")
}
Completely unrelated and could run before or after the "did this finish" code, we schedule a block on queue2
.
What you probably meant was:
let queue1 = DispatchQueue(label: "com.matt.myqueue1")
let group1 = DispatchGroup()
group1.enter()
// Kick off async stuff.
// These usually return quickly, so there's no need for your own queue.
// At some point, when you want to say this is "done", often in some
// completion handler, you call group1.leave(), for example:
... completionHandler: { group1.leave() }
// When all that finishes, print
group.notify(queue: queue1) { print("did this finish?") }
dispatchGroup.notify(queue: inheriting QOS from the current context
With, notify(qos:flags:queue:execute:)
, you can specify .inheritQoS
:
group.notify(flags: .inheritQoS, queue: queue) {
...
}
Catch NSNotification from another GCD queue
- addObserverForName:object:queue:usingBlock: method is an extra feature provided by NSOperationQueue class which is based on Grand Central Dispatcher:
Operation queues use the
libdispatch
library (also known as Grand Central Dispatch) to initiate the execution of their operations.
(from the beginning of the NSOperationQueue
class reference)
This feature can be re-implemented if there are reasons for that (e.g. different behaviour or educational purposes), otherwise it may be worth switching to NSOperationQueue
instead of bare GCD.
Dispatch group - cannot notify to main thread
After reading post suggested by Matt, I found that I was submitting task to main queue and when I asked to be notified on main thread itself, it got in the deadlock.
I have altered the code and now it is working as intended,
typealias CallBack = (result: [Int]) -> Void
func longCalculations (completion: CallBack) {
let backgroundQ = DispatchQueue.global(attributes: .qosDefault)
let group = DispatchGroup()
var fill:[Int] = []
for number in 0..<100 {
group.enter()
backgroundQ.async(group: group, execute: {
if number > 50 {
fill.append(number)
}
group.leave()
})
}
group.notify(queue: DispatchQueue.main, execute: {
print("All Done"); completion(result: fill)
})
}
longCalculations(){print($0)}
Related Topics
Saving Bool/ Tableview Checkmark - 3Rd Time Lucky
Uibuttons Are Not Correctly Shaped on All Devices
Expanding Uitextview Inside a Stack View with Scrolling Enabled
Swift 2.2 Decrementing Specific for Loop in Swift 3
From Which Direction Swift Starts to Read Dictionaries
How to Make Mglpolylines Selectable? - Swift, Mapbox
Send Keyevent to a Target Window via Process Id
Unexpectedly Found Nil While Unwrapping an Optional Value Parsing JSON Swift
How to Disambiguate a Foreach Loop in Xcode with Swiftui
Check If the Username Exist in Firebase
How to Ensure Make Sure I'm Not Accessing Data Until It's Loaded In
How to Deal with Commas When Writing Objects to CSV in Swift
How to Reset a Subview in Swiftui