2017-02-14 1 views
1

Vous essayez d'obtenir le nom d'une ville, tout en ayant la latitude et la longitude. A l'intérieur d'une classe de modèle Location, j'utilise la fonction reverseGeocodeLocation(location: , completionHandler:) fournie avec CLGeocoder (qui fait partie de CoreLocation).Récupérer des données à partir du gestionnaire d'exécution asynchrone

func getLocationName() { 

    let geoCoder = CLGeocoder() 
    let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude) 

    geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in 
     guard let addressDict = placemarks?[0].addressDictionary else { 
      return 
     } 

     if let city = addressDict["City"] as? String { 
      self.currentCity = city 
      print(city) 
     } 
     if let zip = addressDict["ZIP"] as? String { 
      print(zip) 
     } 
     if let country = addressDict["Country"] as? String { 
      print(country) 
     } 
    }) 
} 

Cependant, ViewController, après l'exécution du getLocationName(), le location.currentCity est nil, puisque le gestionnaire d'achèvement est async, et n'a pas été encore terminé.

Comment puis-je m'assurer que le gestionnaire de complétion a fini de fonctionner afin que je puisse accéder à location.currentCity?

+0

Juste accès 'location.currentCity' ** ** dans le gestionnaire d'achèvement ou ajouter un autre gestionnaire d'achèvement' getLocationName() 'pour retourner les données de manière asynchrone . – vadian

+0

Vous ne "vérifiez pas que le gestionnaire de complétion a fini de tourner", vous faites juste ce que vous voulez faire avec 'location.currentCity' dans le' completionHandler' –

+0

@vadian je dois accéder à 'location.currentCity' dans la vue contrôleur, (en dehors de la classe Location) pour mettre à jour l'interface utilisateur. Sera-t-il préférable d'ajouter un autre gestionnaire d'achèvement afin de ne pas mettre à jour l'interface utilisateur dans une classe de modèle? Pouvez-vous fournir un exemple de code indiquant comment ce nouveau gestionnaire de complétion doit être implémenté? –

Répondre

2

Passez une fermeture en tant que un paramètre de fonction dans votre getLocationName que vous pouvez appeler à l'intérieur de la fermeture de reverseGeocodeLocation.

func updateLocation(currentCity : String) -> Void 
{ 
    print(currentCity) 
} 

func getLocationName(callback : @escaping (String) -> Void) 
{ 

    let geoCoder = CLGeocoder() 
    let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude) 

    geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in 
    guard let addressDict = placemarks?[0].addressDictionary else { 
     return 
    } 


    if let city = addressDict["City"] as? String 
    { 
     self.currentCity = city 
     callback(city) 

     print(city) 
     } 
     if let zip = addressDict["ZIP"] as? String { 
     print(zip) 
     } 
     if let country = addressDict["Country"] as? String { 
     print(country) 
     } 
    }) 
} 

Dans votre ViewController ...

getLocationName(callback: updateLocation) 
+0

pas tout à fait comprendre ce qui est à l'intérieur de rappel ... Mais vous me avez donné quelques idées: Comment pourrais-je définir «currentCity» dans le rappel? Je peux le faire car le callback ne sera implémenté qu'après le gestionnaire de complétion. Droite? –

+0

Le rappel sera appelé lorsque le gestionnaire d'achèvement est terminé. vous pouvez définir currentCity dans la fonction updateLocation, voir mon exemple, et vous pouvez ajouter cette fonction dans votre ViewController. –

+0

a eu un tas d'erreurs: Sur 'func getLocationName (callback: (location: CLLocation))' - Impossible de créer un tuple mono-élément avec un libellé d'élément. Sur 'callback (location)' - Impossible d'appeler la valeur du type de non-fonction 'CLLocation' et sur 'print (location.currentCity) '- La valeur de type' CLLocation 'n'a aucun membre' currentCity ' –

0

je créerais une fonction où location.currentCity est utilisé, et appeler cette fonction à partir du gestionnaire d'achèvement

Donc, si votre code ressemble à:

func foo() { 
    var location 
    getLocationName() 
    print(location.currentcity) // nil 
} 

changement à:

func foo() { 
    var location 
    getLocationName() 
} 

func bar() { 
    print(location.currentcity) // someplace 
} 

et la barre d'appel() de votre gestionnaire d'achèvement

+0

Merci, ce que les commentateurs ont suggéré aussi. Cependant, bar() est situé dans une autre classe (dans ViewController). Je veux mettre à jour l'interface utilisateur dans la barre(). Devrais-je créer une instance de viewController et exécuter 'updateUI()' dessus, dans le fichier de modèle de localisation? –