NSURLSession delegates not called
From my testing, you have to choose whether you want to use a delegate or a completion handler - if you specify both, only the completion handler gets called. This code gave me running progress updates and the didFinishDownloadingToURL
event:
func downloadEpisodeWithFeedItem(episodeURL: NSURL) { let request: NSURLRequest = NSURLRequest(URL: episodeURL) let config = NSURLSessionConfiguration.defaultSessionConfiguration() let session = NSURLSession(configuration: config, delegate: self, delegateQueue: NSOperationQueue.mainQueue()) let downloadTask = session.downloadTaskWithURL(episodeURL) downloadTask.resume()}func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) { println("didResumeAtOffset: \(fileOffset)")}func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { var downloadProgress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite) println("downloadProgress: \(downloadProgress)")}func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) { println("didFinishDownloadingToURL: \(location)") println(downloadTask)}
From the NSURLSession
documentation, here's the relevant section:
Like most networking APIs, the NSURLSession API is highly asynchronous. It returns data in one of two ways, depending on the methods you call:
- To a completion handler block that returns data to your app when a transfer finishes successfully or with an error.
- By calling methods on your custom delegate as the data is received.
- By calling methods on your custom delegate when download to a file is complete.
So by design it returns data to either a completion handler block or a delegate. But as evinced here, not both.
Interestingly, Apple specifically explains this behavior in their NSURLSessionDataDelegate
(but neither in the base delegate NSURLSessionTaskDelegate
nor in NSURLSessionDownloadDelegate
)
NOTE
An NSURLSession object need not have a delegate. If no delegate is assigned, when you create tasks in that session, you must provide a completion handler block to obtain the data.
Completion handler block are primarily intended as an alternative to using a custom delegate. If you create a task using a method that takes a completion handler block, the delegate methods for response and data delivery are not called.
Swift 3
class ViewController: UIViewController { var urlLink: URL! var defaultSession: URLSession! var downloadTask: URLSessionDownloadTask!}// MARK: Button Pressed @IBAction func btnDownloadPressed(_ sender: UIButton) { let urlLink1 = URL.init(string: "https://github.com/VivekVithlani/QRCodeReader/archive/master.zip") startDownloading(url: urlLink!)} @IBAction func btnResumePressed(_ sender: UIButton) { downloadTask.resume()}@IBAction func btnStopPressed(_ sender: UIButton) { downloadTask.cancel()}@IBAction func btnPausePressed(_ sender: UIButton) { downloadTask.suspend()} func startDownloading (url:URL) { let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession") defaultSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main) downloadProgress.setProgress(0.0, animated: false) downloadTask = defaultSession.downloadTask(with: urlLink) downloadTask.resume() }// MARK:- URLSessionDownloadDelegatefunc urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { print("File download succesfully")}func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { downloadProgress.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)}func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { downloadTask = nil downloadProgress.setProgress(0.0, animated: true) if (error != nil) { print("didCompleteWithError \(error?.localizedDescription)") } else { print("The task finished successfully") }}