Friday, October 7, 2022
HomeiOS Developmentios - Limiting the variety of fetch requests in URLSession with SwiftUI?

ios – Limiting the variety of fetch requests in URLSession with SwiftUI?


everybody, first query right here!
I am utilizing an async picture loader to fetch photographs from a URLRequest, and I am attempting to wrap my code inside an Operation so I can use .maxConcurrentOperationCount for an OperationQueue, as a result of I am imagined to restrict the variety of downloads to three at a time.. I’ve overriden the Operation class to try to help async downloads, nevertheless, I am not in a position to obtain this, and I believe it is as a result of my downloading perform is inside a Activity group.

The error i get is as follows:
Invalid conversion from ‘async’ perform of sort ‘(URL?, URLResponse?, (any Error)?) async throws -> Void’ to synchronous perform sort ‘(URL?, URLResponse?, (any Error)?) -> Void’

Listed here are the code snippets:

for the overriden Operation class:


class DownloadOperation: Operation {
    personal var process: URLSessionDataTask!
    
    init(session: URLSession, downloadTaskURL: URLRequest, completionHandler: ((URL?, URLResponse?, Error?) -> Void)?) {
           tremendous.init()
           
           // use weak self to stop retain cycle
           process = session.dataTask(with: downloadTaskURL, completionHandler: { [weak self] (URLRequest, response, error) in
               
   
               
              /*
                set the operation state to completed as soon as
                the obtain process is accomplished or have error
              */
               self?.state = .completed
           })
       }
    
    enum OperationState : Int {
            case prepared
            case executing
            case completed
        }

    personal var state : OperationState = .prepared {
          willSet {
              self.willChangeValue(forKey: "isExecuting")
              self.willChangeValue(forKey: "isFinished")
          }
          
          didSet {
              self.didChangeValue(forKey: "isExecuting")
              self.didChangeValue(forKey: "isFinished")
          }
      }
      
      override var isReady: Bool { return state == .prepared }
      override var isExecuting: Bool { return state == .executing }
      override var isFinished: Bool { return state == .completed }
    
    
    override func begin() {
         /*
         if the operation or queue received cancelled even
         earlier than the operation has began, set the
         operation state to completed and return
         */
         if(self.isCancelled) {
             state = .completed
             return
         }
         
         // set the state to executing
         state = .executing
         
         print("downloading")
               
         // begin the downloading
         self.process.resume()
     }

     override func cancel() {
         tremendous.cancel()
       
         // cancel the downloading
         self.process.cancel()
     }
}

and right here is me attempting to make use of it inside a process within the loader perform:

  public func loadImage(_ urlRequest: URLRequest) async throws -> UIImage {
        if let standing = photographs[urlRequest]{
            swap standing{
            case .fetched(let picture):
                return picture
            case .inProgress(let process):
                return strive await process.worth
            case .failure(let error):
                self.hasError = true
                self.error = error as? InternetError
            }
        }
        
        
        let process: Activity<UIImage, Error> = Activity {
            do {
                let imageQueue = OperationQueue()
                imageQueue.maxConcurrentOperationCount = 3
                
                let operation = DownloadOperation(session: URLSession.shared, downloadTaskURL: urlRequest, completionHandler: {_, response ,_ in
                    let (imageData, response) = strive await URLSession.shared.information(for: urlRequest)

                    guard let httpResponse = response as? HTTPURLResponse,
                          httpResponse.statusCode == 200 else {
                        throw InternetError.invalidServerResponse
                    }
                    guard let picture = UIImage(information: imageData) else {
                        throw InternetError.noInternet
                    }
                    
                })
                imageQueue.addOperation(operation)
                
                
                
               // return picture
            }
            catch {
                self.hasError = true
                photographs[urlRequest] = .failure(error)
                print("error caught in Loader")
                let picture = UIImage(systemName: "wifi.exclamationmark")!
                return picture
            }
        }
        
        do{
            photographs[urlRequest] = .inProgress(process)
            var picture = strive await process.worth
            if let imageFromCache = imageCache.object(forKey: urlRequest as AnyObject) as? UIImage {
                picture = imageFromCache
                return picture
            }
            photographs[urlRequest] = .fetched(picture)
            //storing picture in cache
            imageCache.setObject(picture, forKey: urlRequest as AnyObject)
            return picture
        }
    }
}

I’d admire any assist about this! Thanks!!

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments