6

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!

0

1 Answer 1

15

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 }) 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.