Search code examples
swiftresponsensurlsessioncompletionhandler

NSURLSession Response String completion block - Swift


I want to wait for a responseString to complete before calling the next function "nextScreen()" (segue). At the moment I have an if statement to make sure it is not nil before proceeding, but sometimes the the next function/segue is called because the responseString is still downloading.

Could you help with a completion block? I have found completion blocks for NSURLSession, but these just wait for the initial HTTP call to complete, not the response string.

func getProfiles(){
    func post(completion: (message: String?) -> Void) {
        let request = NSMutableURLRequest(URL: NSURL(string: "http://**.**.**.**/EPG/XML/QueryProfile")!)
        request.HTTPMethod = "POST"
        let postString = "<QueryProfileReq><type>1</type></QueryProfileReq>"
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)

        let task: Void = NSURLSession.sharedSession().dataTaskWithRequest(request,
            completionHandler: {(data: NSData!,
                response: NSURLResponse!,
                error: NSError!) in
                if error != nil {
                    println("error=\(error)")
                    let alert = UIAlertView()
                    alert.delegate = self
                    alert.title = "Login Error"
                    alert.message = "\(error)"
                    alert.addButtonWithTitle("OK")
                    alert.show()
                    self.view.endEditing(true)
                    return
                }
                if let responseString = NSString(data: data, encoding: NSUTF8StringEncoding) {
                    if response != nil {
                        println("got profiles")
                        self.nextScreen()
                    }
                    self.dataVar = data // UPDATES VARIABLE TO SEND
                }
        }).resume()

    }
}

Solution

  • The convenience method of dataTaskWithRequest essentially returns data or error, with usually some response header type information. If you have an error then you won't have data (99% sure about this). I have re formatted your method to help. The NSString Init Convenience method is synchronous so not quite sure by what you mean by waiting to complete instead of http call?

    func getStringFromRequest(completionHandler:(success:Bool, data: NSData?) -> Void) {
    
        let request = NSMutableURLRequest(URL: NSURL(string: "http://##.##.##.##/EPG/XML/QueryProfile")!)
        request.HTTPMethod = "POST"
        let postString = "<QueryProfileReq><type>1</type></QueryProfileReq>"
        request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
    
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) -> Void in
    
            if let unwrappedError = error {
                print("error=\(unwrappedError)")
            }
            else {
                if let unwrappedData = data {
                    completionHandler(success: true, data: unwrappedData)
                    return
                }
            }
    
            completionHandler(success: false, data: nil)
        }
    
        task?.resume()
    }
    
    func performPost() {
    
        getStringFromRequest { (success, data) -> Void in
    
            if (success) {
    
                if let unwrappedData = data {
    
                    self.dataVar = unwrappedData
    
                    if let responseString = NSString(data: unwrappedData, encoding: NSUTF8StringEncoding) {
                        self.nextScreen()
                    }
                }
            }
            else {
                print("Failed")
            }
        }
    }