How can I use Dispatch barrier for updating dictionary photoDownloadTasks
which holds key as image url string and completion block to return downloaded image from URLSession?
Please suggest.
class ImageService {
static let shared = ImageService()
let barrierQueue = DispatchQueue(label: "com.download.tasks", attributes: .concurrent)
typealias completionHandler = (Result<UIImage, ImageFetchError>) -> Void
var photoDownloadTasks = [String: [completionHandler]]()
func downloadPhoto(from url: String?, completion: @escaping (Result<UIImage, ImageFetchError>) -> Void) -> Cancellable? {
var cancellable: Cancellable?
guard let urlString = url else { return cancellable }
// Update dictionary
barrierQueue.async(flags: .barrier) {
if self.photoDownloadTasks.keys.contains(urlString) {
self.photoDownloadTasks[urlString]?.append(completion)
return nil // ERROR: Unexpected non-void return value in void function
} else {
self.photoDownloadTasks[urlString] = [completion]
}
}
guard let url = URL(string: urlString) else {
completion(.failure(.invalidRequestURL))
return cancellable
}
// networkService.request(url: url) <=> URLSession.shared.dataTask(url:url)
cancellable = networkService.request(url: url) { [weak self] result in
switch result {
case .success(let data):
guard let downloadedImage = UIImage(data: data) else {
completion(.failure(.invalidImage))
return
}
// execute all blocks store in dictionary
barrierQueue.sync {
guard let completionHandlers = self?.photoDownloadTasks[urlString] else { return }
for handler in completionHandlers {
handler(.success(downloadedImage))
}
self?.photoDownloadTasks[urlString] = nil
}
case .failure(let error):
completion(.failure(error))
}
}
return cancellable
}
}