Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift DispatchGroup notify before task finish

I'm using DispatchGroup to perform a task, but group.notify is being called before the task is completed.

My code:

let group = DispatchGroup()
let queueImage = DispatchQueue(label: "com.image")
let queueVideo = DispatchQueue(label: "com.video")
queueImage.async(group: group) {
    sleep(2)
    print("image")
}

queueVideo.async(group: group) {
    sleep(3)
    print("video")
}

group.notify(queue: .main) {
    print("all finished.")
}

Logs:

all finish.
image
video
like image 657
Victor Avatar asked Mar 20 '18 04:03

Victor


3 Answers

Update: The question above actually runs correctly as is (as rmaddy pointed out!)

I'm saving this wrong answer below in case others get confused about DispatchQueue's async(group:) methods behavior, since Apple's swift doc on it is currently lousy.


The group's enter() needs to be called before each call to async(), and then the group's leave() needs to be called at end of each async() block, but within the block. It's basically like a refcount that when it reaches zero (no enters remaining), then the notify block is called.

let group = DispatchGroup()
let queueImage = DispatchQueue(label: "com.image")
let queueVideo = DispatchQueue(label: "com.video")

group.enter()
queueImage.async(group: group) {
    sleep(2)
    print("image")
    group.leave()
}

group.enter()
queueVideo.async(group: group) {
    sleep(3)
    print("video")
    group.leave()
}

group.notify(queue: .main) {
    print("all finished.")
}
like image 178
Smartcat Avatar answered Nov 06 '22 06:11

Smartcat


Generic answer : (Swift 5)

let yourDispatchGroup = DispatchGroup()

yourDispatchGroup.enter()
task1FunctionCall {
  yourDispatchGroup.leave() //task 1 complete
}

yourDispatchGroup.enter()
task2FunctionCall {
  yourDispatchGroup.leave() //task 2 complete
}

.. ..
yourDispatchGroup.enter()
tasknFunctionCall {
  yourDispatchGroup.leave() //task n complete
}

dispatchGroup.notify(queue: .main) {
  //This is invoked when all the tasks in the group is completed.
}
like image 45
iPhoneDeveloper Avatar answered Nov 06 '22 07:11

iPhoneDeveloper


If your DispatchGroup is a lazy var, try to not call the notify method inside the initialization code block.

lazy var dispatchGroup: DispatchGroup = {
    let dispatchGroup = DispatchGroup()
    
    // not call here dispatchGroup.notify(...

    return dispatchGroup
}()

You need to call all the enter methods before the notify method:

dispatchGroup.enter()

dispatchQueue.async(group: dispatchGroup) {
    // ...
    self.dispatchGroup.leave()
}

dispatchGroup.notify(queue: .main) {
    print("all finished.")
}
like image 1
pableiros Avatar answered Nov 06 '22 07:11

pableiros