2016-11-12 200 views
0

嗯,我是Swift的新手,我不太了解完成处理程序。我想从API获取请求并解析JSON响应,以便我可以获取令牌。但是我的代码发生了什么事情:每当我调用getAuthentication函数时,我的UI冻结并等待数据获取。这里是getAuthentication的代码异步API请求的同步API请求Swift 2.2

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); 
} 

然后,我在我的LoginViewController中调用这个方法。有人说我正在使用Synchronous请求,这就是为什么我的UI冻结,但我真的不知道如何将其更改为Async并等待数据下载。有人可以帮我弄这个吗?任何帮助将不胜感激。

+0

结帐[Alamofire](https://github.com/Alamofire/Alamofire)。这是执行异步HTTP请求的方便框架。 –

+0

简单地摆脱信号量;你正在阻止主线程。你需要在完成关闭时处理响应 – Paulw11

+0

@Reginald,这里使用的'NSURLSession'的'dataTaskWithRequest'函数是一个异步函数。这里不需要使用'dispatch_queue'。你可以检查我的答案。随时对任何疑问发表评论 – KrishnaCA

回答

2

首先,从您的功能中删除dispatch_semaphore相关的代码。

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() 
} 

在上面的代码中,函数dataTaskWithRequest本身是一个asynchronus功能。所以,你不需要在后台线程中调用getAuthentication功能。

如在添加完成处理程序,

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() 
} 

它可以被称为如下:

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

}) 
+0

谢谢!这工作!好吧,我忘了dispatch_async这就是为什么我没有得到任何东西,即使我正在做完成处理程序 – Reginald

+0

欢迎:) – KrishnaCA

1

您可以将一个转义的闭包参数传​​递给getAuthentication方法。

func getAuthentication(username: String, password: String, completion: (JSON) ->()){ 
    ... 
    // create a request in the same way 
    ... 
    let session = NSURLSession.sharedSession() 
    let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in 
     if error == nil{ 
      let swiftyJSON = JSON(data: data!) 
      print(swiftyJSON) 
      completion(swiftyJSON) 
     } else { 
      print("There was an error") 
     } 
    } 
    task.resume() 
} 

并调用getAuthentication在LoginViewController这样的:

getAuthentication(username, password) { (json) -> in 
    //Do whatever you want with the json result 
    dispatch_async(dispatch_get_main_queue()) { 
     // Do UI updates 
    } 
} 

另一种方式去呼吁getAuthentication在后台线程在LoginViewController以避免阻塞主线程(即UI线程)。

//In LoginViewController 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
     getAuthentication(username, password) 
     dispatch_async(dispatch_get_main_queue()) { 
     // UI updates 
    } 
}