ios - google - mapkit tutorial
Swift-CLGeocoder reverseGeocodeLocio finalizaciónHandler cierre (6)
Aquí está el cierre que funcionó para mí: me tomó un tiempo hacerlo funcionar. Creo que su problema está relacionado con no inicializar p con el inicializador correcto. Intenté algunas variaciones hasta que funcionó: self.placemark = CLPlacemark (placemark: stuff [0] as 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
}
})
EDITAR:
Movió mejor respuesta a su propia respuesta.
Lo que estoy tratando de hacer es pasar una CLLocation
a la función getPlacemarkFromLocation
que luego usa la CLLocation
pasada a través de reverseGeocodeLocation
para establecer la CLPlacemark?
Eso será devuelto.
Estoy teniendo problemas para crear el cierre de reverseGeocodeLocation
de reverseGeocodeLocation
en reverseGeocodeLocation
, se está reverseGeocodeLocation
un error / bloqueo del compilador:
En Swift, CLGeocodeCompletionHandler
es CLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Void
AnyObject[]!
acuerdo con la documentación AnyObject[]!
se supone que contiene objetos CLPlacemark
al igual que la versión Objective-C.
Aquí está mi código actual:
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?
}
EDITAR: Parece que el error tuvo que ver con placemarks.count
de placemarks
. Cuenta con placemarks.count
de placemarks
no se tratan como una matriz. Se compila ahora, sin embargo, no obtengo nada más que nada al tratar de establecer p
dentro de la completionHandler
. He comprobado las CLLocation
están pasando y son válidas.
EDIT 2: Después de imprimir placemarks
, puedo confirmar que devuelve datos. Sin embargo, p
sigue regresando a cero.
Con estas líneas de Swift, puede imprimir completamente la dirección de la ubicación:
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)
}
})
}
¡Aclamaciones!
EDIT: Esto no funciona. El valor es nulo fuera del cierre - vea los comentarios a continuación
Su p es nulo porque el cierre lo captura antes de que se inicialice a una referencia. Para obtener el comportamiento que desea, debe hacer que pa no sea un valor opcional, como var p: CLPlacemark !.
A continuación se muestra el código que usé para probar mi conjetura:
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)")
}
Aquí está el registro de la consola:
Pushit <- botón presionado para iniciar la captura de ubicación
Fuera de lo que está en p: vacío
Dentro de lo que está en p: Estados Unidos
Fuera de lo que está en p: vacío
Dentro de lo que está en p: Estados Unidos
Fuera de lo que está en p: vacío ...
Encontré la respuesta que necesitaba en este hilo: Establecer cadena de dirección con reverseGeocodeLocation: y regresar desde el método
El problema radica en el hecho de que reverseGeocodeLocation
es asíncrono, el método está devolviendo un valor antes de que se reverseGeocodeLocation
el reverseGeocodeLocation
p
en mi ejemplo.
Según lo solicitado, aquí está mi código actual.
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) }
})
}
No quise tomar la ruta NSNotificationCenter porque eso agregaría una sobrecarga innecesaria, más bien dentro del cierre de CLPlacemark
getPlacemarkFromLocation
, getPlacemarkFromLocation
otra función y paso el CLPlacemark
generado por getPlacemarkFromLocation
como parámetro para mantener las cosas asincrónicas, ya que la función se llamará después de las placemarks
configura la función (debería) recibir la marca de posición necesaria y ejecuta el código que deseas. Espero que lo que dije tenga sentido.
Poco tarde en esta fiesta, pero parece que necesitas (ed) hacer una lectura inicial sobre cosas asíncronas. Dicho esto, probablemente ya lo hayas aprendido.
El problema básico con tu código es que p (tu marca de posición) se configura después de que la función regresa, por lo que simplemente se pierde: no puedes usar una función para devolver un valor con async. Con un cierre de finalización, su código pasa la marca de posición cuando llega (de forma asíncrona) y se invoca el cierre; tenga en cuenta que la función ahora no devuelve nada.
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)
})
}
Utilizar -
getPlacemarkFromLocation(myLocation, completion: { (placemark) in
// do something with the placemark here
})
Realmente no he puesto esto en Xcode, pero se ve bien ...
Tus cosas no funcionan por varias razones. Aquí está la parte que arreglé sin mirar realmente la funcionalidad:
class func getPlacemarkFromLocation(location:CLLocation)->CLPlacemark?{
var g = CLGeocoder()
var p:CLPlacemark?
g.reverseGeocodeLocation(location, completionHandler: {
(placemarks, error) in
let pm = placemarks!
if (pm.count > 0){
p = placemarks![0]
}
})
return p
}