Reputation: 449
I understand how to use a dispatch group in a simple for-loop. I, however, have a more complicated for-loop with more asynchronous calls within it. I want all the asynchronous calls to complete before executing the group completion code. I have tried to apply the principles in this answer to no avail- Can I use dispatch group not in a loop?. Here is my code, based off of the techniques I observed in that link:
let group = DispatchGroup()
for ref in self.notifsRefList {
group.enter()
self.db.fetch(withRecordID: ref.recordID) { notifRecord, notifErr in
print("async call")
if notifErr == nil {
// do stuff
if let ref = notifRecord?.object(forKey: POST) as! CKReference? {
group.enter()
self.db.fetch(withRecordID: ref.recordID) { postRecord, err in
print("async call")
if err == nil {
// do stuff
group.leave()
}
else {
print("\(err)")
group.leave()
}
}
}
if let ref = notifRecord?.object(forKey: USER_NOTIF) as! CKReference? {
self.db.fetch(withRecordID: ref.recordID) { userRecord, err2 in
group.enter()
print("async call")
if err2 == nil {
// do stuff
group.leave()
}
else {
print("\(err2)")
group.leave()
}
}
}
if let ref = notifRecord?.object(forKey: LIBRARY_ITEM) as! CKReference? {
self.db.fetch(withRecordID: ref.recordID) { libRecord, err3 in
group.enter()
print("async call")
if err3 == nil {
// do stuff
group.leave()
}
else {
print("\(err3)")
group.leave()
}
}
}
group.leave()
}
else {
print("\(notifErr)")
group.leave()
}
}
}
group.notify(queue: .main, execute: { // executed after all async calls in for loop finish
print("done with all async calls")
// do stuff
})
From the print statements I included, I know that my asynchronous calls are incorrect: sometimes "done with all async calls" prints before all instances of "async call." Any help in how to get this dispatch group working properly would be much appreciated. Thanks!
Upvotes: 6
Views: 7336
Reputation: 318794
The problem is the 2nd and 3rd inner async calls. You are calling group.enter()
inside the completion blocks instead of before the async calls.
There's also no need for so many calls to leave
.
You need to move the two as follows:
let group = DispatchGroup()
for ref in self.notifsRefList {
group.enter()
self.db.fetch(withRecordID: ref.recordID) { notifRecord, notifErr in
print("async call")
if notifErr == nil {
// do stuff
if let ref = notifRecord?.object(forKey: POST) as! CKReference? {
group.enter()
self.db.fetch(withRecordID: ref.recordID) { postRecord, err in
print("async call")
if err == nil {
// do stuff
}
else {
print("\(err)")
}
group.leave()
}
}
if let ref = notifRecord?.object(forKey: USER_NOTIF) as! CKReference? {
group.enter()
self.db.fetch(withRecordID: ref.recordID) { userRecord, err2 in
print("async call")
if err2 == nil {
// do stuff
}
else {
print("\(err2)")
}
group.leave()
}
}
if let ref = notifRecord?.object(forKey: LIBRARY_ITEM) as! CKReference? {
group.enter()
self.db.fetch(withRecordID: ref.recordID) { libRecord, err3 in
print("async call")
if err3 == nil {
// do stuff
}
else {
print("\(err3)")
}
group.leave()
}
}
}
else {
print("\(notifErr)")
}
group.leave()
}
}
group.notify(queue: .main, execute: { // executed after all async calls in for loop finish
print("done with all async calls")
// do stuff
})
Upvotes: 15