NSURLSession delegates not called NSURLSession delegates not called ios ios

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