Tracking Download Progress by using delegate

Sellen Wei
2 min readJul 13, 2018

--

I recently working on a project that need to download all url files in an object and tracking the progress of the downloading and represent the progress indication, let user know what is the downloading status is.

My original though was:

class FileDownloader: NSObject, URLSessionDownloadDelegate {
func startDowloadFileAndSaveLocally(completion:@escaping () -> Void)
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
}

In this way, I could use FileDownloader to help me download file and use other two functions from URLSessionDownloadDelegate to get download progress and complete info.

this FileDownloader will be generate in upper layer class called FileDownloadManager class :

class FileDownloadManager: NSObject{
func downloadAndSaveLargeFiles(urlList:[url])
func removeLargeFiles(urlList:[url])
}

and this manager will be used in an viewController, when user click on the download button, background thread will start download files by using FileDownloadManager.

This whole flow works fine, I could print out the status of each individual download task, but at view controller level, I could not get the download status for each individual task. And when I start inject progress indicator, I find this very annoying, because my download status is so deep I could not get info at upper level and update progress bar immediately.

I find delegate could help me solve this issue. And what I learn today refresh the understand of delegate. In simple word, delegate is an object in lower level, that could update UI/function/variable in upper level by calling delegate’s function! (you also could replace the word “lower” and “upper” to “one” and “another”)

firstly, we know by using delegate, we need to have 1. a protocol. 2. a class implement this protocol and set delegate to itself. 3. another lower level class call delegate.function to actually use delegate’s function. I will not spend time to explain the basic of delegate, let start explain in code!

  1. a protocol
@objc protocol DownloadDelegate: class {    func downloadProgressUpdate(for progress: Float)}

2. a class implement and use this delegate/protocol

class SetupCookwareInstructionsViewController: UIViewController,DownloadDelegate {    self.fileDownloadManager.delegate = self;    func downloadProgressUpdated(_ progress: Float) {
DispatchQueue.main.async(execute: {
self.progbar.progress = progress
})
}
}

3. a lower level class that call the delegate function

class FileDownloadManager: NSObject{    var delegate: DownloadDelegate?
func downloadAndSaveLargeFiles(urlList:[url]){
for url in urlList{
filedownloader.startDowloadFileAndSaveLocally(completion:
{
delegate.downloadProgressUpdated()
})
}
}
//other functions
}

In this way, by calling the lower level function “downloadAndSaveLargeFiles” we could successfully update upper level’s UI in view controller.

Reference file: https://medium.com/journey-of-one-thousand-apps/tracking-download-progress-with-swift-c1a13f3f8c66

--

--