Hey everyone! I'm creating a custom Image Loader application and I need to be able to limit the number of URLRequests sent at a time. I have considered using dispatch Semaphores, however, my function to fetch photos is supposed to be asynchronous. I will include the code below. I have also considered to create an Async Operation object but that also did not work out. Does anyone have any suggestions for how to achieve this functionality?
public func loadImage(_ urlRequest: URLRequest) async throws -> UIImage {
if let status = images[urlRequest]{
switch status{
case .fetched(let image):
return image
case .inProgress(let task):
return try await task.value
case .failure(let error):
self.hasError = true
self.error = error as? InternetError
}
}
let task: Task<UIImage, Error> = Task {
do {
// let downloadQueue = DispatchQueue.global(qos: .userInitiated)
// let downloadGroup = DispatchGroup()
let (imageData, response) = try await URLSession.shared.data(for: urlRequest)
downloadSemaphore.signal()
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw InternetError.invalidServerResponse
}
guard let image = UIImage(data: imageData) else {
throw InternetError.noInternet
}
return image
}
catch {
self.hasError = true
images[urlRequest] = .failure(error)
print("error caught in Loader")
let image = UIImage(systemName: "wifi.exclamationmark")!
return image
}
}
let blockOperation = BlockOperation {
self.downloadSemaphore.wait()
}
opeQueue.maxConcurrentOperationCount = 1
opeQueue.addOperation(blockOperation)
do{
images[urlRequest] = .inProgress(task)
var image = try await task.value
if let imageFromCache = imageCache.object(forKey: urlRequest as AnyObject) as? UIImage {
image = imageFromCache
return image
}
images[urlRequest] = .fetched(image)
//storing image in cache
imageCache.setObject(image, forKey: urlRequest as AnyObject)
return image
}
}
}