Ce que j'essaie de faire est de passer un CLLocation
à la fonction getPlacemarkFromLocation
qui utilise ensuite le CLLocation
passé à reverseGeocodeLocation
pour définir le CLPlacemark?
qui sera renvoyé.
J'ai des problèmes pour créer la fermeture completionHandler
dans reverseGeocodeLocation
, il génère une erreur/crash du compilateur:
Dans Swift, CLGeocodeCompletionHandler
est CLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Void
selon la documentation. AnyObject[]!
est censé contenir des objets CLPlacemark
, tout comme la version d'Objective-C.
Voici mon code actuel:
class func getPlacemarkFromLocation(location:CLLocation)->CLPlacemark?{
var g = CLGeocoder()
var p:CLPlacemark?
g.reverseGeocodeLocation(location, completionHandler: {
(placemarks, error) in
let pm = placemarks as? CLPlacemark[]
if (pm && pm?.count > 0){
p = placemarks[0] as? CLPlacemark
}
})
return p?
}
EDIT: Il semble que l’erreur concerne placemarks.count
avec placemarks
ne pas être traité comme un tableau. Il compile maintenant, cependant je n’obtiens rien mais nil lorsque j'essaie de placer p
dans le completionHandler
. J'ai vérifié le CLLocation
s étant passé et ils sont valides.
EDIT 2: Après avoir imprimé placemarks
, je peux confirmer que les données sont renvoyées. Cependant, p
renvoie toujours zéro.
J'ai trouvé la réponse dont j'avais besoin dans ce fil de discussion: Définir la chaîne d'adresse avec reverseGeocodeLocation: et renvoyer depuis la méthode
Le problème réside dans le fait que reverseGeocodeLocation
est asynchrone, la méthode renvoie une valeur avant que0000LachidationBlock définit p
dans mon exemple.
Comme demandé, voici mon code actuel.
func showAddViewController(placemark:CLPlacemark){
self.performSegueWithIdentifier("add", sender: placemark)
}
func getPlacemarkFromLocation(location: CLLocation){
CLGeocoder().reverseGeocodeLocation(location, completionHandler:
{(placemarks, error) in
if error {println("reverse geodcode fail: \(error.localizedDescription)")}
let pm = placemarks as [CLPlacemark]
if pm.count > 0 { self.showAddPinViewController(placemarks[0] as CLPlacemark) }
})
}
Je ne voulais pas prendre la route NSNotificationCenter car cela ajouterait une surcharge inutile. Plutôt dans la fermeture completionHandler
, j'appelle une autre fonction et transmets la CLPlacemark
générée par getPlacemarkFromLocation
en tant que paramètre pour que les choses restent asynchrones car la fonction sera appelée après placemarks
définir la fonction (devrait) recevoir le repère nécessaire et exécuter le code souhaité. J'espère que ce que j'ai dit est logique.
Avec ces lignes de Swift, vous pouvez imprimer intégralement l'adresse du lieu:
func getLocationAddress(location:CLLocation) {
var geocoder = CLGeocoder()
println("-> Finding user address...")
geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error)->Void in
var placemark:CLPlacemark!
if error == nil && placemarks.count > 0 {
placemark = placemarks[0] as CLPlacemark
var addressString : String = ""
if placemark.ISOcountryCode == "TW" /*Address Format in Chinese*/ {
if placemark.country != nil {
addressString = placemark.country
}
if placemark.subAdministrativeArea != nil {
addressString = addressString + placemark.subAdministrativeArea + ", "
}
if placemark.postalCode != nil {
addressString = addressString + placemark.postalCode + " "
}
if placemark.locality != nil {
addressString = addressString + placemark.locality
}
if placemark.thoroughfare != nil {
addressString = addressString + placemark.thoroughfare
}
if placemark.subThoroughfare != nil {
addressString = addressString + placemark.subThoroughfare
}
} else {
if placemark.subThoroughfare != nil {
addressString = placemark.subThoroughfare + " "
}
if placemark.thoroughfare != nil {
addressString = addressString + placemark.thoroughfare + ", "
}
if placemark.postalCode != nil {
addressString = addressString + placemark.postalCode + " "
}
if placemark.locality != nil {
addressString = addressString + placemark.locality + ", "
}
if placemark.administrativeArea != nil {
addressString = addressString + placemark.administrativeArea + " "
}
if placemark.country != nil {
addressString = addressString + placemark.country
}
}
println(addressString)
}
})
}
À votre santé!
Voici la fermeture qui a fonctionné pour moi - il a fallu un certain temps pour que cela fonctionne. Je pense que votre problème est lié au fait de ne pas initialiser p avec le bon initialiseur. J'ai essayé quelques variantes jusqu'à ce que cela fonctionne: self.placemark = CLPlacemark (repère: stuff [0] comme CLPlacemark)
geocoder.reverseGeocodeLocation(newLocation, completionHandler: {(stuff, error)->Void in
if error {
println("reverse geodcode fail: \(error.localizedDescription)")
return
}
if stuff.count > 0 {
self.placemark = CLPlacemark(placemark: stuff[0] as CLPlacemark)
self.addressLabel.text = String(format:"%@ %@\n%@ %@ %@\n%@",
self.placemark.subThoroughfare ? self.placemark.subThoroughfare : "" ,
self.placemark.thoroughfare ? self.placemark.thoroughfare : "",
self.placemark.locality ? self.placemark.locality : "",
self.placemark.postalCode ? self.placemark.postalCode : "",
self.placemark.administrativeArea ? self.placemark.administrativeArea : "",
self.placemark.country ? self.placemark.country : "")
}
else {
println("No Placemarks!")
return
}
})
MODIFIER:
déplacé meilleure réponse à sa propre réponse.
Un peu en retard pour cette soirée, mais il semble que vous ayez besoin de faire des lectures approfondies sur le contenu asynchrone. En disant cela, vous l'avez probablement déjà appris.
Le problème fondamental de votre code est que p (votre repère) est défini après le retour de la fonction. Il est donc tout simplement perdu. Vous ne pouvez pas utiliser une fonction pour renvoyer une valeur asynchrone. Avec une fermeture complète, votre code se voit attribuer le repère dès son arrivée (de manière asynchrone) et la fermeture est invoquée - notez que la fonction ne renvoie plus rien.
func getPlacemarkFromLocation(_ location: CLLocation, completion: ((CLPlacemark?) -> ())) {
CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in
// use optional chaining to safely return a value or nil
// also using .first rather than checking the count & getting placemarks[0] -
// if the count is zero, will just give you nil
// probably a good idea to check for errors too
completion(placemarks?.first)
})
}
Utilisation -
getPlacemarkFromLocation(myLocation, completion: { (placemark) in
// do something with the placemark here
})
En fait, je n'ai pas mis cela dans Xcode, mais ça a l'air bien ...
EDIT: Cela ne fonctionne pas. La valeur est nulle en dehors de la fermeture - voir les commentaires ci-dessous
Votre p est nul parce que la fermeture le capture avant qu'il ne soit initialisé à une référence. Pour obtenir le comportement souhaité, vous devez définir p comme valeur non optionnelle telle que var p: CLPlacemark !.
Ci-dessous le code que j'ai utilisé pour tester ma conjecture:
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
var g = CLGeocoder()
var p:CLPlacemark?
let mynil = "empty"
g.reverseGeocodeLocation(newLocation, completionHandler: {
(placemarks, error) in
let pm = placemarks as? CLPlacemark[]
if (pm && pm?.count > 0){
// p = CLPlacemark()
p = CLPlacemark(placemark: pm?[0] as CLPlacemark)
println("Inside what is in p: \(p?.country ? p?.country : mynil)")
}
})
println("Outside what is in p: \(p?.country ? p?.country : mynil)")
}
Voici le journal de la console:
Pushit <- bouton enfoncé pour lancer la capture de la position
En dehors de ce qui est dans p: vide
À l'intérieur de ce qui est dans p: États-Unis
En dehors de ce qui est dans p: vide
À l'intérieur de ce qui est dans p: États-Unis
En dehors de ce qui est dans p: vide ...