B L B L - 1 year ago 115
Swift Question

Show loading percentage of image download from url with swift

So I have an image downloading from a url like so

let request = NSMutableURLRequest(URL: NSURL(string: "\(self.ip)")!)
request.HTTPMethod = "POST"
let postString = "userID=\(userID)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession(configuration: configuration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())

let task = session.dataTaskWithRequest(request) {
data, response, error in

and my delegate functions look like

func URLSession(session: NSURLSession, task: NSURLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {

let uploadProgress:Float = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
let progressPercent = Int(uploadProgress*100)

func URLSession(session: NSURLSession, dataTask: NSURLSessionDataTask, didBecomeDownloadTask downloadTask: NSURLSessionDownloadTask) {
let downloadProgress:Float = Float(downloadTask.countOfBytesReceived) / Float(downloadTask.countOfBytesExpectedToReceive)

The upload progress works just fine for a different function, but when downloading an image, the second URLSession function does not get called. What am I doing wrong?

Answer Source

NSURLSession has 5 types of delegate: NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate and NSURLSessionStreamDelegate. You can read about them in the documentation.

The ones you need to care about are NSURLSessionDelegate and NSURLSessionDownloadDelegate:

class ViewController: UIViewController, NSURLSessionDelegate, NSURLSessionDownloadDelegate {

    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var progressView: UIProgressView!

    override func viewDidLoad() {

    override func didReceiveMemoryWarning() {

    @IBAction func downloadImage(sender : AnyObject) {
        // A 20MB image from NASA
        let url = NSURL(string: "http://eoimages.gsfc.nasa.gov/images/imagerecords/78000/78314/VIIRS_3Feb2012_lrg.jpg")!

        let config = NSURLSessionConfiguration.defaultSessionConfiguration()
        let session = NSURLSession(configuration: config, delegate: self, delegateQueue: nil)

        // Don't specify a completion handler here or the delegate won't be called
        let task = session.downloadTaskWithURL(url)     

    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        print("Downloaded \(totalBytesWritten) / \(totalBytesExpectedToWrite) bytes ")

        dispatch_async(dispatch_get_main_queue()) {
            self.progressView.progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)

    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
        // The location is only temporary. You need to read it or copy it to your container before
        // exiting this function. UIImage(contentsOfFile: ) seems to load the image lazily. NSData
        // does it right away.
        if let data = NSData(contentsOfURL: location), image = UIImage(data: data) {
            dispatch_async(dispatch_get_main_queue()) {
                self.imageView.contentMode = .ScaleAspectFit
                self.imageView.clipsToBounds = true
                self.imageView.image = image
        } else {
            fatalError("Cannot load the image")