Hello everyone,
my app downloads a couple of files from a server, using a URLSessionDataTask
. When a downloads finishes successfully (and without any errors), then it should start the next download (=next loop iteration). If there is any type of error, then the whole thing has to abort and display the error message through the calling function (I've got my own error enum class that doesn't throw an error for that). If it finishes without any errors, then it simply switches back to the calling function.
This function is called after another dataTask
has finished (using a completion handler) but I never switch back to the main thread, so all of this is still running in the same background thread the previous task used.
My code (Swift 5, Xcode 14.2):
private func fileDownload(fileNames fns:[String]) {
if !errorBool {
print("Main thread: \(Thread.isMainThread)")
let group = DispatchGroup()
myloop:
for f in fns {
let url = getURL(f)
group.enter()
//DispatchQueue.global(qos: .background).async {
let task = session.dataTask(with: url) {(data, response, error) in
defer { group.leave() }
print("Starting task!")
if error != nil && data == nil {
self.errorBool = true
break myloop //TODO 1: "Cannot find label 'myloop' in scope", "self." doesn't help
}
if let httpResponse = response as? HTTPURLResponse {
//Do stuff with downloaded data, more error handling that sets the error flag and message
}
}
task.resume()
//}
//TODO 2: How do I wait here for the task to finish?
//group.wait()
if errorBool {
break myloop
}
}
group.notify(queue: .main) {
print("Done!")
//Displays any errors in a popup (on the main thread) through the calling function
}
}
}
There are two things that I'm experiencing problems with:
- How do I break the loop from within the task if there's an error ("TODO 1")? I might be able to replace the first
break
with areturn
with the same result but I'm still wondering: Is it possible? - More importantly, how do I wait at "TODO 2" until the task finishes, so I can break the loop if there are any errors? If I use
group.wait()
there, then the task never starts (deadlock?), even though it should automatically run on a background thread. I tried to switch to yet another background thread for the task (see inactive code above) but that didn't help either.
I thought that this is exactly what a DispatchGroup
is used for but is it really or am I just using it incorrectly? Is there anything else that can accomplish a "wait" within this single function? I found a little bit of information about a Semaphore
but no exact info how to do it in my case and some people even recommend not using semaphores anymore.