2016-11-12 197 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 
    } 
}