2016-11-12 25 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で呼び出しています。私は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 thatsを忘れました – 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() 
} 

そして、このようLoginViewControllerでgetAuthenticationを呼び出す:どこへ行く

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

もう一つの方法は、メインスレッド(すなわち、UIスレッドを)ブロックを避けるために、あなたのLoginViewControllerのバックグラウンドスレッドでgetAuthenticationを呼んでいます。

//In LoginViewController 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) { 
     getAuthentication(username, password) 
     dispatch_async(dispatch_get_main_queue()) { 
     // UI updates 
    } 
} 
関連する問題