I have the following code, which uses a DispatchGroup to get notified when the tasks are done like this:
func getSomething(completion: ()->()) {
completion()
}
func doSomeWork(completion: ()->()) {
let myGroup: DispatchGroup = DispatchGroup()
for _ in 0..<10 {
myGroup.enter()
getSomething {
myGroup.leave()
}
}
myGroup.notify(queue: DispatchQueue.main) { // this here is the key
completion()
}
}
DispatchQueue.global().async {
print("We are doing background work")
doSomeWork {
print("We are done with the work - but on main thread now!!!")
}
}
So the issue I have is that I call some function on a thread, that function has a completion which is called on some fixed queue.
My options are:
But I am not happy with any of the options... I'd rather not have so many dispatches.
Imagine this:
DispatchQueue.global().async {
print("We are doing background work")
doSomeWork {
DispatchQueue.global().async {
print("Now we are in background again")
}
}
}
That is already a level-3 closure and is not really nice to work with especially if in that background async call we have another closure or level.
Any help on what to do here would be great! Thank you
The issue is that I‘m calling a function bla({ //block code }) on a background queue. bla() calls the completion handler on the main thread though, due to dispatch groups – Janosch Hübner
check again your snippet
func doSomeWork(completion: ()->()) {
let myGroup: DispatchGroup = DispatchGroup()
for _ in 0..<10 {
myGroup.enter()
getSomething {
myGroup.leave()
}
}
myGroup.notify(queue: DispatchQueue.main) { // this here is the key
completion()
}
}
and see, that because getSomething is synchronous you could simply write
func doSomeWork(completion: ()->()) {
//let myGroup: DispatchGroup = DispatchGroup()
for _ in 0..<10 {
//myGroup.enter()
getSomething {
//myGroup.leave()
}
}
//myGroup.notify(queue: DispatchQueue.main) { // this here is the key
completion()
//}
}
In case getSomething should be asynchronous, use the proper API to run it within some group
func doSomeWork(completion: ()->()) {
let myGroup: DispatchGroup = DispatchGroup()
let queue = DispatchQueue.global()
for _ in 0..<10 {
//myGroup.enter()
queue.async(group: myGroup) {
getSomething {
//myGroup.leave()
}
}
}
myGroup.notify(queue: DispatchQueue.main) { // this here is the key
completion()
}
}
Running completion() on the same thread (it is better to say on the same queue) as doSomeWork(completion: ()->()) is simple.
func doSomeWork(completion: ()->()) {
let myGroup: DispatchGroup = DispatchGroup()
let queue = DispatchQueue.global()
for _ in 0..<10 {
//myGroup.enter()
queue.async(group: myGroup) {
getSomething {
//myGroup.leave()
}
}
}
//myGroup.notify(queue: DispatchQueue.main) { // this here is the key
myGroup.wait()
completion()
//}
}
check next playground page and see how DispatchQueue.concurrentPerform could change your design and how goup notification works
import PlaygroundSupport
import Dispatch
PlaygroundPage.current.needsIndefiniteExecution = true
let q0 = DispatchQueue.global()
let q1 = DispatchQueue(label: "my_queue", attributes: .concurrent)
let g = DispatchGroup()
let g1 = DispatchGroup()
q0.async(group: g) {
print("1 message from \(q0): will do some concurrent jobs in the background")
DispatchQueue.concurrentPerform(iterations: 5, execute: { (i) in
sleep(1)
print("\t",i)
})
print("2 message from \(q0): all concurrent jobs done")
q0.async(group: g) {
print("3 some other long time running on group...")
sleep(3)
print("3 ex")
}
q0.async(group: g1) {
print("? some other long time running on gifferent group...")
sleep(4)
print("? ex")
}
g1.notify(queue: .main, execute: {
print("g1 empty")
})
}
print("4 continue on main")
g.notify(queue: q1) {
print("5 message from \(q1): finished a")
DispatchQueue.main.async {
sleep(1)
print("6 from main, should stop playground execution?")
//PlaygroundPage.current.finishExecution()
}
print("7 message from \(q1): finished b")
}
g1.notify(queue: .main) {
print("8 from main, g1 is empty.")
}
print(" ... continue")
which prints on my environment
1 message from <OS_dispatch_queue_global: com.apple.root.default-qos>: will do some concurrent jobs in the background
4 continue on main
... continue
8 from main, g1 is empty.
0
2
1
3
4
2 message from <OS_dispatch_queue_global: com.apple.root.default-qos>: all concurrent jobs done
3 some other long time running on group...
? some other long time running on gifferent group...
3 ex
5 message from <OS_dispatch_queue_concurrent: my_queue>: finished a
7 message from <OS_dispatch_queue_concurrent: my_queue>: finished b
6 from main, should stop playground execution?
? ex
g1 empty
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With