1

Im using NSURLSession which is preferred according to this thread. How to make an HTTP request in Swift?

let url = NSURL(string: "http://www.stackoverflow.com")

let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
    println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

task.resume()

My only problem is when user taps twice and I want to cancel the first request. I have tried task.cancel() but the print statement is still executed (namely right after .cancel() with NSDomainError). How do I safely cancel this request (NSURLSessionDataTask), without firing the print statement, or is it even possible?

EDIT: Just to be clear. The URL could be the same and I want to cancel the first request.

Community
  • 1
  • 1
Zeezer
  • 1,503
  • 2
  • 18
  • 33
  • Does the print statement or `NSDomainError` specify that the task was cancelled? If it does, just switch on that and ignore that error, since you are expecting it. – keithbhunter Jun 16 '15 at 12:31
  • 1
    possible duplicate of [How to find and cancel a task in NSURLSession?](http://stackoverflow.com/questions/23518690/how-to-find-and-cancel-a-task-in-nsurlsession) – LoVo Jun 16 '15 at 12:56
  • @LoVo No thats a different question (he has problems finding the task), also I asked for how to do this in swift. – Zeezer Jun 16 '15 at 13:04
  • @keithbhunter Im looking into this now, seems like its solvable in an ugly way. – Zeezer Jun 16 '15 at 13:04
  • But the answers are correct, put your task in an array and if you want to cancel one of them, check the state. The code might be in obj-c but it should easy enough to migrate. – LoVo Jun 16 '15 at 13:08
  • @LoVo The answer is not correct. He suggest checking against a URL, what if the URL is the same? Then how am I supposed to know which session is which? – Zeezer Jun 16 '15 at 13:24

2 Answers2

1

This is how I solved the problem. When task.cancel() is performed, the print statement wont be executed. Seems a little hacky to check against a string so if anyone has a better solution I will accept that one.

let url = NSURL(string: "http://www.stackoverflow.com")

let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
    if (error?.userInfo?["NSLocalizedDescription"] as? String) == "cancelled"
            {
                return
            }
    println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

task.resume()
Zeezer
  • 1,503
  • 2
  • 18
  • 33
  • to avoid checking against a string i did: if let err = error as? NSURLError { if err == NSURLError.Cancelled { print("❌ request cancelled") } } – scord Oct 12 '15 at 20:54
1

I hope this is something you can use:

class ViewController: UIViewController , NSURLSessionDownloadDelegate {

    var download : NSURLSessionDownloadTask?
    var backgroundSession : NSURLSession?

    override func viewDidLoad() {
        super.viewDidLoad()

        let sessionConfiguration : NSURLSessionConfiguration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("CustomBackgroundIdentifier")
        backgroundSession = NSURLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: NSOperationQueue.mainQueue())

        var btn = UIButton(frame: CGRectMake(0, 0, 100, 100))
        btn.backgroundColor = UIColor.redColor()
        btn.addTarget(self, action: "startDownload", forControlEvents: UIControlEvents.TouchDown)
        self.view.addSubview(btn)

        var btn2 = UIButton(frame: CGRectMake(0, 120, 100, 100))
        btn2.backgroundColor = UIColor.blueColor()
        btn2.addTarget(self, action: "cancelDownload", forControlEvents: UIControlEvents.TouchDown)
        self.view.addSubview(btn2)

    }

    func startDownload() {
        if download == nil {
            if let url = NSURL(string: "http://www.stackoverflow.com") {
                download = backgroundSession?.downloadTaskWithURL(url)
                download?.resume()
            }
        } else {
            resumeDownload()
        }
    }

    func pauseDownload() {
        if download != nil {
            download?.suspend()
        }
    }

    func resumeDownload() {
        if download != nil {
            download?.resume()
        }
    }

    func cancelDownload() {
        if download != nil {
            download?.cancel()
        }
    }

    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL) {
        println("Session %@ download task %@ finished downloading to URL %@\n",
        session, downloadTask, location)
    }

    func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        println("downloaded: %i",totalBytesWritten)
    }
}
LoVo
  • 1,856
  • 19
  • 21
  • 1
    Should you be using `download!.resume()` instead of `download?.resume()` (and others) since you've already wrapped it in a `nil` check? – Ryan R Oct 31 '15 at 22:19