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)
}
}
}
}
}
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: