Kill request

I created a code that request information to webservice, the user typing the word and the app request the information, the webservice return a json. The code worked ok. But I use search bar and a schedule time, when the user stoped to type, the information is requested.

The problem is, if the app request information and the user start typing again the app finish the first request and after request the second information. I need that, when the user request again, the app kill the first request and start second request. Is it possible?


this is the example:


var lastScheduledSearch: NSTimer?
@IBOutlet weak var searchBar: UISearchBar!

..

func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
        lastScheduledSearch?.invalidate() /
   
        lastScheduledSearch = NSTimer.scheduledTimerWithTimeInterval(1.5, target: self, selector: "startSearching:", userInfo: searchText, repeats: false)
    }

func startSearching(timer: NSTimer) {
        let searchText = timer.userInfo as! String
    
        search(searchText)
    }

func search(searchText: String) {
        let operation = NSBlockOperation()
        operation.addExecutionBlock {
            self.dataController.find(searchText){jsonData, error in
                if let json: AnyObject! = jsonData {
                    self.data = json as! NSArray
                  
                    dispatch_async(dispatch_get_main_queue()) {
                        self.tableView.reloadData()
                    }
                }
            }
          
        }
        currentOperation = operation
        operationQueue.addOperation(currentOperation!)
    }

//class that request json to webservice

func find(search: String,completion: (jsonData: NSArray?, error: NSError?)->Void){
       
        var jsonData:NSArray = []
       
        let post:NSString = "data=\(search)"
       
        let url:NSURL = NSURL(string: links_web.find() as String)!
       
        let postData:NSData = post.dataUsingEncoding(NSUTF8StringEncoding)!
       
        let postLength:NSString = String( postData.length )
       
        let request:NSMutableURLRequest = NSMutableURLRequest(URL: url)
        request.HTTPMethod = "POST"
        request.HTTPBody = postData
        request.setValue(postLength as String, forHTTPHeaderField: "Content-Length")
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.setValue("application/json", forHTTPHeaderField: "Accept")
       
       
        let session = NSURLSession.sharedSession()
        let task = session.dataTaskWithRequest(request) {urlData, response, reponseError in
           
            if let receivedData = urlData {
                let res = response as! NSHTTPURLResponse!;
               
                NSLog("Response code: %ld", res.statusCode);
               
                if 200..<300 ~= res.statusCode {
                    do {
                        jsonData = try NSJSONSerialization.JSONObjectWithData(receivedData, options: []) as! NSArray
                        /
                        completion(jsonData: jsonData, error: nil)
                    } catch let error as NSError {
                        
                        completion(jsonData: nil, error: returnedError)
                    }
                } else {
                    
                    completion(jsonData: nil, error: returnedError)
                }
            } else {
                var userInfo: [NSObject: AnyObject] = [
                    "title": "Error!",
                    "message": "Conection fail"
                ]
                if let error = reponseError {
                    userInfo["message"] = error.localizedDescription
                    userInfo["cause"] = error
                }
                let returnedError = NSError(domain: ".", code: 2, userInfo: userInfo)
                /
                completion(jsonData: nil, error: returnedError)
            }
        }
        task.resume()
   
    }
Answered by DTS Engineer in 85920022

You need to call

cancel()
on your NSURLSessionDataTask object, that is, the thing you got back from
dataTaskWithRequest(xxx)
. Right now you can’t do that because you’re storing your only reference to that object in
task
, which is a local variable. junkpile is recommending that you put it into a property (perhaps
currentTask
) at which point you can call
cancel
on it before starting a new task.

IMPORTANT A cancelled task still completes, just with an error. You should check for that error. Also, you’ll want some sort of serialisation to ensure that you don’t commit results from a cancelled task. Given that your results will eventually be committed to the UI (which is main thread only) your commit serialisation could be as simple as bouncing over to the main thread.

Also, I’m going to point you to a technote I wrote about this, Technote 2109 Simple and Reliable Threading with NSOperation and its associated ListAdder sample code. While it’s cast in terms of NSOperation, many of the same problems, and solutions, apply when you use NSURLSession like this.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Yes, you just need to keep a reference to the NSURLSessionDataTask in progress (currently only stored in your local variable "task"). Put it in a property instead, and call cancel() on it.

Sorry I did not understand

I need call cancel() on function "find" but, How can I use "NSURLSessionDataTask" ? I need create other method? Or I need change on function find?

Accepted Answer

You need to call

cancel()
on your NSURLSessionDataTask object, that is, the thing you got back from
dataTaskWithRequest(xxx)
. Right now you can’t do that because you’re storing your only reference to that object in
task
, which is a local variable. junkpile is recommending that you put it into a property (perhaps
currentTask
) at which point you can call
cancel
on it before starting a new task.

IMPORTANT A cancelled task still completes, just with an error. You should check for that error. Also, you’ll want some sort of serialisation to ensure that you don’t commit results from a cancelled task. Given that your results will eventually be committed to the UI (which is main thread only) your commit serialisation could be as simple as bouncing over to the main thread.

Also, I’m going to point you to a technote I wrote about this, Technote 2109 Simple and Reliable Threading with NSOperation and its associated ListAdder sample code. While it’s cast in terms of NSOperation, many of the same problems, and solutions, apply when you use NSURLSession like this.

Share and Enjoy

Quinn "The Eskimo!"
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thanks Eskimo for your help and documentation, thanks Junpile for your help.

Kill request
 
 
Q