Reginald Reginald - 24 days ago 13
iOS Question

Synchronous API request to Asynchronous API request Swift 2.2

Well I am new to Swift and I don't know much of completion handler. I want to get a request from an API and parse the JSON response so I can get the token. But what's happening with my code is that whenever I call the

getAuthentication
function my UI freezes and waiting for the data to get. Here is the code for
getAuthentication


func getAuthentication(username: String, password: String){
let semaphore = dispatch_semaphore_create(0);
let baseURL = "Some URL here"
let url = NSURL(string: baseURL)!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = "{\n \"username\": \"\(username)\",\n \"password\": \"\(password)\"\n}".dataUsingEncoding(NSUTF8StringEncoding);

let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

if error == nil{
let swiftyJSON = JSON(data: data!)
print(swiftyJSON)

//parse the data to get the user
self.id = swiftyJSON["id"].intValue
self.token = swiftyJSON["meta"]["token"].stringValue
} else {
print("There was an error")
}
dispatch_semaphore_signal(semaphore);
}
task.resume()
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}


then, I am calling this method in my LoginViewController. Someone says that I am using a Synchronous request thats why my UI freezes, but I have really no idea on how to change it to Async and wait for the data to be downloaded. Can someone help me with this? Any help will much be appreciated.

Answer

Firstly, remove dispatch_semaphore related code from your function.

func getAuthentication(username: String, password: String){

   let baseURL = "Some URL here"
   let url = NSURL(string: baseURL)!
   let request = NSMutableURLRequest(URL: url)
   request.HTTPMethod = "POST"
   request.HTTPBody = "{\n  \"username\": \"\(username)\",\n  \"password\": \"\(password)\"\n}".dataUsingEncoding(NSUTF8StringEncoding);

   let session = NSURLSession.sharedSession()
   let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

       if error == nil{
          let swiftyJSON = JSON(data: data!)
          print(swiftyJSON)

          //parse the data to get the user
          self.id = swiftyJSON["id"].intValue
          self.token = swiftyJSON["meta"]["token"].stringValue
       } else {
          print("There was an error")
       }
   }
   task.resume()
}

In the above code, the function dataTaskWithRequest itself is an asynchronus function. So, you don't need to call the function getAuthentication in a background thread.

For adding the completion handler,

func getAuthentication(username: String, password: String, completion:((sucess: Bool) -> Void)){

   let baseURL = "Some URL here"
   let url = NSURL(string: baseURL)!
   let request = NSMutableURLRequest(URL: url)
   request.HTTPMethod = "POST"
   request.HTTPBody = "{\n  \"username\": \"\(username)\",\n  \"password\": \"\(password)\"\n}".dataUsingEncoding(NSUTF8StringEncoding);

   let session = NSURLSession.sharedSession()
   let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

       var successVal: Bool = true

       if error == nil{
          let swiftyJSON = JSON(data: data!)
          print(swiftyJSON)
          self.id = swiftyJSON["id"].intValue
          self.token = swiftyJSON["meta"]["token"].stringValue
       } else {
          print("There was an error")
          successVal = false
       }

       dispatch_async(dispatch_get_main_queue(), { () -> Void in
          completion(successVal)                 
       })
   }
   task.resume()
}

It can be called as follows:

self.getAuthentication("user", password: "password", completion:  {(success) -> Void in

})