0

I'm using my downloader class to download files through URLSession delegate method and updating progress bar with progress from the delegate method. I call the download class like this from my View:

downloader.download(url: self.video.url, fileName: self.video.filePath)

After this is complete I want to update some variables in my View to stop showing the progress bar. I was thinking of using a completion handler but I don't think this would really work whilst using the delegate for progress and completion. And I can't access the variables of my view to update in the completion delegate method of downloader.

I was wondering if it would be possible to use the delegate method for progress updates and a completion handler for completion? Is this possible?

Do you have any ideas how I could do it?

Here is my downloader class:

class download: NSObject, URLSessionDelegate, URLSessionDownloadDelegate{

    @ObservedObject var globalScrollTitle: ScrollTitle = ScrollTitle.sharedInstance

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64){

        let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
        DispatchQueue.main.async(execute: {
            self.globalScrollTitle.mainprogress = CGFloat(progress)
            print(self.globalScrollTitle.mainprogress)
        })
    }

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        // check for and handle errors:
        // * downloadTask.response should be an HTTPURLResponse with statusCode in 200..<299
        print("download complete!")

        do{
            let downloadedData = try Data(contentsOf: location)

            DispatchQueue.main.async(execute: {
                print("transfer completion OK!")

                let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.downloadsDirectory, .userDomainMask, true).first! as NSString
                let destinationPath = documentDirectoryPath.appendingPathComponent((downloadTask.response?.suggestedFilename)!)

                let pdfFileURL = URL(fileURLWithPath: destinationPath)
                FileManager.default.createFile(atPath: pdfFileURL.path,
                                               contents: downloadedData,
                                               attributes: nil)

                if FileManager.default.fileExists(atPath: pdfFileURL.path) {
                    print("file present!") // Confirm that the file is here!
                }
            })
        } catch {
            print (error.localizedDescription)
        }


    }

    func download(url: String, fileName: String) {
        let myUrl = URL(string: url)
        let request = URLRequest(url:myUrl!)
        //let config = URLSessionConfiguration.default
        //let operationQueue = OperationQueue()
        let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
        let downloadTask = session.downloadTask(with: request)
        downloadTask.resume()
        //completion()
    }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
Joshg345
  • 74
  • 8
  • Does this answer your question? [get progress from dataTaskWithURL in swift](https://stackoverflow.com/questions/30543806/get-progress-from-datataskwithurl-in-swift) – Faysal Ahmed Apr 20 '20 at 06:06
  • Thanks for your help! I managed to find the answer using that link. – Joshg345 Apr 21 '20 at 07:15

1 Answers1

0

Thanks to Faysal Ahmed, I managed to find the following solution that worked. This allowed me to track my progress to update UI whilst also using a completion handler.

    observation = task.progress.observe(\.fractionCompleted) { progress, _ in
        DispatchQueue.main.async(execute: {
            self.globalScrollTitle.mainprogress = CGFloat(progress.fractionCompleted)
        })
        if progress.fractionCompleted == 1 {
            completion()
        }
    }

My download func now looks like this:

func download(url: String, fileName: String, completion: @escaping () -> Void) {
        let myUrl = URL(string: url)
        let request = URLRequest(url:myUrl!)
        let config = URLSessionConfiguration.default
        let operationQueue = OperationQueue()
        let session = URLSession(configuration: config, delegate: nil, delegateQueue: operationQueue)

        let task = session.dataTask(with: request) { (data, response, error) in
            guard error == nil else {
                print(error!)
                return
            }
            // Success
            if let statusCode = (response as? HTTPURLResponse)?.statusCode {
                print("Success: \(statusCode)")
            }

            do {
                let documentFolderURL = try FileManager.default.url(for: .downloadsDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
                let fileURL = documentFolderURL.appendingPathComponent(fileName)
                try data!.write(to: fileURL)

                DispatchQueue.main.async {

                    if FileManager.default.fileExists(atPath: fileURL.path) {
                        print("file present!") // Confirm that the file is here!
                    }
                }

            } catch  {
                print("error writing file \(error)")
            }
        }

        observation = task.progress.observe(\.fractionCompleted) { progress, _ in
            DispatchQueue.main.async(execute: {
                self.globalScrollTitle.mainprogress = CGFloat(progress.fractionCompleted)
            })
            if progress.fractionCompleted == 1 {
                completion()
            }
        }

        task.resume()
    }
}
Joshg345
  • 74
  • 8