I use dispatch group in a loop in order to keep track an array of network requests so when they are all successfully completed then the successful completion handler is returned only once.
However, if a single failure occur, I want to abort the entire operation and return the failure completion handler only once. The problem I am facing is that all failure completion handlers are returned multiple times. Which is not what I want.
My code looks something like this.
class NetworkClient {
// ...
func fetchBlogPosts(completion: @escaping (Result<[BlogPost], NetworkClientError>) -> Void) {
let dispatchGroup = DispatchGroup()
var blogPosts = [BlogPost]()
for (index, value) in blogPostJSONURLs.enumerated() {
dispatchGroup.enter()
guard let jsonURL = URL(string: blogPostJSONURLs[index]) else {
dispatchGroup.leave()
completion(.failure(.invalidURL))
return
}
let dataTask = URLSession.shared.dataTask(with: jsonURL) { data, response, error in
if error != nil {
dispatchGroup.leave()
completion(.failure(.errorReturned))
return
}
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
dispatchGroup.leave()
completion(.failure(.serverError))
return
}
guard let data = data else {
dispatchGroup.leave()
completion(.failure(.noData))
return
}
do {
let blogPost = try JSONDecoder().decode(BlogPost.self, from: data)
blogPosts.append(blogPost)
dispatchGroup.leave()
} catch {
dispatchGroup.leave()
completion(.failure(.failedToDecodeJSON))
}
}
dataTask.resume()
}
dispatchGroup.notify(queue: .main) {
completion(.success(blogPosts))
}
}
}