In the following code, the file downloads just fine. However none of the delegate methods seem to be called as I receive no output whatsoever. the progressView is not updated either. Any idea why?
import Foundation
import UIKit
class Podcast: PFQueryTableViewController, UINavigationControllerDelegate, MWFeedParserDelegate, UITableViewDataSource, NSURLSessionDelegate, NSURLSessionDownloadDelegate {
func downloadEpisodeWithFeedItem(episodeURL: NSURL) {
var request: NSURLRequest = NSURLRequest(URL: episodeURL)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)
var downloadTask = session.downloadTaskWithURL(episodeURL, completionHandler: { (url, response, error) -> Void in
println("task completed")
if (error != nil) {
println(error.localizedDescription)
} else {
println("no error")
println(response)
}
})
downloadTask.resume()
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didResumeAtOffset fileOffset: Int64, expectedTotalBytes: Int64) {
println("didResumeAtOffset")
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
var downloadProgress = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
println(Float(downloadProgress))
println("sup")
epCell.progressView.progress = Float(downloadProgress)
}
func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
println(location)
}
}
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.
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:- URLSessionDownloadDelegate
func 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")
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With