Ограничение количества запросов на выборку в URLSession с помощью SwiftUI?
Я использую асинхронный загрузчик изображений для извлечения изображений изURLRequest
, и я пытаюсь обернуть свой код внутри операции, чтобы я мог использовать.maxConcurrentOperationCount
дляOperationQueue
, потому что я должен ограничить количество загрузок до 3 за раз.
Я переопределил класс Operation, чтобы попытаться поддерживать асинхронную загрузку, однако я не могу этого добиться, и я думаю, это потому, что моя функция загрузки находится внутриTask
группа.
Ошибка, которую я получаю, выглядит следующим образом:
Недопустимое преобразование из «асинхронной» функции типа «(URL?, URLResponse?,(любая ошибка)?) async throws -> Void» в тип синхронной функции «(URL?, URLResponse?,(любая ошибка)?) -> Void'
Вот фрагменты кода:
для переопределенного класса операции:
class DownloadOperation: Operation {
private var task: URLSessionDataTask!
init(session: URLSession, downloadTaskURL: URLRequest, completionHandler: ((URL?, URLResponse?, Error?) -> Void)?) {
super.init()
// use weak self to prevent retain cycle
task = session.dataTask(with: downloadTaskURL, completionHandler: { [weak self] (URLRequest, response, error) in
/*
set the operation state to finished once
the download task is completed or have error
*/
self?.state = .finished
})
}
enum OperationState : Int {
case ready
case executing
case finished
}
private var state : OperationState = .ready {
willSet {
self.willChangeValue(forKey: "isExecuting")
self.willChangeValue(forKey: "isFinished")
}
didSet {
self.didChangeValue(forKey: "isExecuting")
self.didChangeValue(forKey: "isFinished")
}
}
override var isReady: Bool { return state == .ready }
override var isExecuting: Bool { return state == .executing }
override var isFinished: Bool { return state == .finished }
override func start() {
/*
if the operation or queue got cancelled even
before the operation has started, set the
operation state to finished and return
*/
if(self.isCancelled) {
state = .finished
return
}
// set the state to executing
state = .executing
print("downloading")
// start the downloading
self.task.resume()
}
override func cancel() {
super.cancel()
// cancel the downloading
self.task.cancel()
}
}
и вот я пытаюсь использовать его внутри задачи в функции загрузчика:
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 imageQueue = OperationQueue()
imageQueue.maxConcurrentOperationCount = 3
let operation = DownloadOperation(session: URLSession.shared, downloadTaskURL: urlRequest, completionHandler: {_, response ,_ in
let (imageData, response) = try await URLSession.shared.data(for: urlRequest)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw InternetError.invalidServerResponse
}
guard let image = UIImage(data: imageData) else {
throw InternetError.noInternet
}
})
imageQueue.addOperation(operation)
// return image
}
catch {
self.hasError = true
images[urlRequest] = .failure(error)
print("error caught in Loader")
let image = UIImage(systemName: "wifi.exclamationmark")!
return image
}
}
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
}
}
}
Буду признателен за любую помощь в этом! Спасибо!!