How to Notify a Queue in Swift (Gcd)

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



Leave a reply



Submit