swiftdownloadprogress-barnsurlsessiondownloadtaskurlsession

Downloading audio files


I have an audio application with multiple controller, VCMain controller where all the books and the VCBook controller are displayed about the book where there is a function of downloading audio files (the book can have many files).

When clicking on the download button appears a round progress bar.

How to do so that when I go back to VCMain and go back to the book that is downloaded I had all the necessary data for the progress bar settings (which books are still downloading or are they downloading at all). I can simultaneously download several books

var progressIndicatorView:CircularProgressView!
lazy var sizeBytes:Int64 = 0
lazy var dowloandedSizeBytes:Int64 = 0


@objc func progressBar(){
    DispatchQueue.main.async {
        self.progressIndicatorView = CircularProgressView(frame: CGRect(x: 5, y: -20, width: 50, height: 50))
        self.view.addSubview(self.progressIndicatorView)
        self.download.isEnabled = false
        self.download.isHidden = true

    }

}

@objc func downloadBook(){

    progressBar()

    for i in UrlName{

        Func.getDownloadSize(url: URL(string: i)!, completion: { [weak self] (size, error) in
            self!.sizeBytes += size
        })

        if let audioUrl = URL(string: i) {
            // create your document folder url
            let documentsUrl = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
            // your destination file url
            let destination = documentsUrl.appendingPathComponent(audioUrl.lastPathComponent)
            // check if it exists before downloading it
            if FileManager().fileExists(atPath: destination.path) {
                print("The file already exists at path")
                bookMarkLoad()
                Func.getDownloadSize(url: URL(string: i)!, completion: { [weak self] (size, error) in
                    self!.dowloandedSizeBytes += size
                })
            } else {
                //  if the file doesn't exist
                //  just download the data from your url
                var url = URLRequest(url: audioUrl)
                url.timeoutInterval = Double.infinity
                let config = URLSessionConfiguration.background(withIdentifier: i)
                let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
                let task = session.downloadTask(with: url)
                task.taskDescription = String(format:"%@" , i )
                task.resume()
                registerBackgroundTask()
              //  let _ = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(backgraundState), userInfo: nil, repeats: true)
            }
        }
    }
}


func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
    if UrlName.contains(downloadTask.taskDescription!){
        if totalBytesExpectedToWrite > 0 {
            dowloandedSizeBytes += bytesWritten
            let progress = Float(dowloandedSizeBytes) / Float(sizeBytes)
            //  print("Progress \(downloadTask) \(progress)")
            DispatchQueue.main.async {
                if self.progressIndicatorView != nil {
                    self.progressIndicatorView.progress = CGFloat(progress)
                }
            }
        }

    }

}

Solution

  • This is quite a broad question, but I would suggest starting by moving all logic related to downloading to a separate service. It is considered good practice to keep such logic away from your views/viewcontrollers.

    This service would be responsible for handling the downloads and can notify other parts of the applications (such as viewcontrollers) of the progress, for example by using notifications.

    The MainVC can then request state information from the service and update the view, for example in the viewWillAppear(_:) method.

    Some examples on how to get starting structuring your app and services can be found at: