2017-07-24 3 views
0

J'essaie d'apprendre Swift, et j'ai un petit projet avec Google API lieux.Résultats URLSession dans les données NIL

J'ai une méthode pour récupérer des détails lieux, qui utilise URLSession en rapide pour envoyer la demande:

func fetchRestaurantDetails(placeId: String) -> Void { 
    let jsonURLString = "https://maps.googleapis.com/maps/api/place/details/json?placeid=\(placeId)&key=[MY API KEY]" 
    guard let url = URL(string: jsonURLString) else { return} 

    let urlRequest = URLRequest(url: url) 

    // set up the session 
    let config = URLSessionConfiguration.default 
    let session = URLSession(configuration: config) 


    _ = session.dataTask(with: urlRequest) { (data, response, error) in 
     // check for any errors 
     guard error == nil else { 
      print("error calling GET on /todos/1") 
      print(error!) 
      return 
     } 
     // make sure we got data 
     guard let responseData = data else { 
      print("Error: did not receive data") 
      return 
     } 
     // parse the result as JSON, since that's what the API provides 
     do { 
      let place = try JSONDecoder().decode(Result.self, from: responseData) // New in Swift 4, used to serialize json. 
      self.rest = place.result 
     } catch { 
      print("error trying to convert data to JSON") 
      return 
     } 
    }.resume() 
} 

J'utilise cette méthode pour créer une instance de restaurants de type, que je vais plus tard ajouter à une liste :

func createRestaurant(placeId: String) -> Restaurants { 
    self.fetchRestaurantDetails(placeId: placeId) 
    let rest = Restaurants(name: self.rest.name, 
          formatted_address: self.rest.formatted_address, 
          website: self.rest.website, 
          location: ((self.rest.geometry.location.lat,self.rest.geometry.location.lng)), 
          opening_hours: self.rest.opening_hours.weekday_text, 
          photo: restImg) 
    return rest! 
} 

Mais chaque fois que j'arrive de nouveau dans les "let repos = Restaurants (...)" toutes les valeurs sont nulles. Lorsque j'essaie de le déboguer, il saute simplement sur mes sections "_ = session" jusqu'à resume(), puis de nouveau à la session et se termine à resume(). Aucune donnée produite. Je suis assez perplexe depuis que j'ai exécuté ce morceau de code avec succès, et maintenant je me demande si j'ai raté quelque chose. Thx :-)

Répondre

1

Mettez deux points d'arrêt. Un à

let place = try JSONDecoder().decode(Result.self, from: responseData) // New in Swift 4, used to serialize json. 
    self.rest = place.result 

et le second à

let rest = Restaurants(name: self.rest.name, 
         formatted_address: self.rest.formatted_address, 
         website: self.rest.website, 
         location: ((self.rest.geometry.location.lat,self.rest.geometry.location.lng)), 
         opening_hours: self.rest.opening_hours.weekday_text, 
         photo: restImg) 

Vous vous rendrez compte que le second est appelé se premier. Vous récupérez des données, ce qui est fait de manière asynchrone, et avant qu'il soit disponible, vous essayez de l'utiliser. Vous devez vous assurer que les données sont disponibles avant de l'utiliser. Une manière ici serait d'utiliser un gestionnaire d'achèvement. Vous pouvez en apprendre davantage sur les gestionnaires d'achèvement here.

+0

Merci! C'était aussi mon propre sentiment initial, mais je suppose que je ne pouvais tout simplement pas envelopper ma tête autour des gestionnaires d'achèvement! THX. – monkally

0

fetchRestaurantDetails est une méthode asynchrone en raison du fait que vous appelez session.dataTask, qui est asynchrone.

Vous essayez d'utiliser les résultats de la fonction avant qu'elle ne soit retournée. Vous avez plusieurs façons de résoudre ce problème:

  1. Utilisez un gestionnaire d'achèvement pour renvoyer la valeur de fetchRestaurantDetails
  2. Utilisez DispatchGroups pour détecter lorsque le URLRequest terminé
  3. Utiliser un cadre 3ème partie comme PromiseKit pour gérer l'asynchrone fonctionne comme des fonctions normales avec des valeurs de retour.