Getting a notification when all async requests have completed.
I call registerTrack
multiple times in the loop below. I want to only trigger the syncGroup.notify
when all requests have been completed. From looking at this code, its going to notify
after each successful completion of registerTrack
. How do I make it signal notify
only after all registerTrack
operations have been completed?
My code is as follows:
var fail = false
let syncGroup = DispatchGroup() //used so we can determine if all the register requests have finished
for track in unsyncedTracks {
syncGroup.enter()
if fail {
syncGroup.leave()
break //might save an aync request from getting executed on failure
}
registerTrack(track: track, withCompletion: { (success: Bool) -> () in
if success {
self.debug.log(tag: "RecordViewController", content: "Registered track: \(track.name)")
syncGroup.leave()
}
else {
fail = true
syncGroup.leave()
}
})
}
//all requests complete
syncGroup.notify(queue: .main) {
if fail {
complete(false)
}
else {
self.debug.log(tag: "RecordViewController", content: "Finished registering all unsynced tracks")
complete(true)
}
}
EDIT:
Based on the recommendation to use GCD concurrent queues, I changed my code to:
var failed = false
//work item to loop through and call registerTrack on each track
let registerTracksWorkItem = DispatchWorkItem {
for track in unsyncedTracks {
if failed { //exit early on failure, potentially save a network request
break
}
self.registerTrack(track: track, withCompletion: { (success: Bool) -> () in
if success {
self.debug.log(tag: "RecordViewController", content: "Registered track: \(track.name)")
}
else {
failed = true
}
})
}
}
//handler for when all registerTrack calls are complete
registerTracksWorkItem.notify(queue: DispatchQueue.main) {
if failed {
self.debug.log(tag: "RecordViewController", content: "At least one registerTrack call failed")
complete(false)
}
else {
self.debug.log(tag: "RecordViewController", content: "Finished registering all unsynced tracks")
complete(true)
}
}
//execute the work item
let queue = DispatchQueue.global()
queue.async(execute: registerTracksWorkItem)
This code does not wait for registerTrack
to finish, rather it executes them all and calls the notify
event. :(
EDIT 3:
So this works. It uses a counter to check to see if its at the final unsyncedTracks
object.
var fail = false
let syncGroup = DispatchGroup() //used so we can determine if all the register requests have finished
//used to make sure notify is only triggered when all registerTracks are complete
let unsyncedTracksCount = unsyncedTracks.count
var completeCounter = 0
syncGroup.enter()
for track in unsyncedTracks {
registerTrack(track: track, withCompletion: { (success: Bool) -> () in
if success {
self.debug.log(tag: "RecordViewController", content: "Registered track: \(track.name)")
}
else {
fail = true
}
completeCounter = completeCounter + 1
if completeCounter == unsyncedTracksCount {
syncGroup.leave()
}
})
}
//all requests complete
syncGroup.notify(queue: .main) {
if fail {
complete(false)
}
else {
self.debug.log(tag: "RecordViewController", content: "Finished registering all unsynced tracks")
complete(true)
}
}
Can I do this (it also appears to work)? I added the if fail, leave()
if.
var fail = false
let syncGroup = DispatchGroup() //used so we can determine if all the register requests have finished
//used to make sure notify is only triggered when all registerTracks are complete
let unsyncedTracksCount = unsyncedTracks.count
var completeCounter = 0
syncGroup.enter()
for track in unsyncedTracks {
if fail { //might save an aync request from getting executed on failure
syncGroup.leave()
break
}
registerTrack(track: track, withCompletion: { (success: Bool) -> () in
if success {
self.debug.log(tag: "RecordViewController", content: "Registered track: \(track.name)")
}
else {
fail = true
}
completeCounter = completeCounter + 1
if completeCounter == unsyncedTracksCount {
syncGroup.leave()
}
})
}
//all requests complete
syncGroup.notify(queue: .main) {
if fail {
complete(false)
}
else {
self.debug.log(tag: "RecordViewController", content: "Finished registering all unsynced tracks")
complete(true)
}
}