2016-11-12 2 views
0

Nun, ich bin neu in Swift und ich weiß nicht viel von Abschluss-Handler. Ich möchte eine Anfrage von einer API erhalten und die JSON-Antwort analysieren, damit ich das Token bekommen kann. Aber was passiert mit meinem Code ist, dass, wenn ich die getAuthentication Funktion meine Benutzeroberfläche einfriert und darauf warten, dass die Daten zu bekommen. Hier ist der Code für getAuthenticationSynchrone API-Anfrage an asynchrone API-Anfrage 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); 
} 

dann rufe ich diese Methode in meinem LoginViewController. Jemand sagt, dass ich eine synchrone Anfrage verwende, deshalb friert meine Benutzeroberfläche ein, aber ich habe wirklich keine Ahnung, wie ich sie in Async ändern und auf den Download der Daten warten kann. Kann mir jemand dabei helfen? Jede Hilfe wird sehr geschätzt werden.

+0

Kasse [Alamofire] (https://github.com/Alamofire/Alamofire). Es ist ein praktisches Framework für asynchrone HTTP-Anfragen. –

+0

Einfach den Semaphor loswerden; Sie blockieren damit den Haupt-Thread. Sie müssen die Antwort in der Abschlussverarbeitung verarbeiten – Paulw11

+0

@Reginald, 'dataTaskWithRequest' Funktion von' NSURLSession' verwendet hier ist eine asynchrone Funktion. Keine Notwendigkeit, 'dispatch_queue' hier zu verwenden. Sie können meine Antwort überprüfen. Fühlen Sie sich frei, für irgendwelche Zweifel zu kommentieren – KrishnaCA

Antwort

2

Erstens entfernen dispatch_semaphore zugehörigen Code aus Ihrer Funktion.

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 dem obigen Code kann die Funktion dataTaskWithRequest selbst ist eine asynchrone Funktion. Sie müssen also die Funktion getAuthentication nicht in einem Hintergrundthread aufrufen.

Für den Abschluss Handler Hinzufügen

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

Es kann wie folgt aufgerufen werden:

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

}) 
+0

danke! das funktioniert! Nun, ich habe das dispatch_async vergessen, weshalb ich nichts bekomme, obwohl ich die Completion Handler mache. – Reginald

+0

du bist willkommen :) – KrishnaCA

1

Sie können ein erledigendes Abschlussargument an die getAuthentication-Methode übergeben.

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

Und nennen getAuthentication in LoginViewController wie folgt aus:

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

Ein anderer Weg getAuthentication in einem Hintergrund-Thread in Ihrem LoginViewController zu gehen ist der Aufruf der Haupt-Thread nicht blockiert werden (das heißt UI-Thread).

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