Swift – CLGeocoder reverseGeocodeLocation completionHandler cierre

Lo que yo estoy tratando de hacer es pasar un CLLocation a la función getPlacemarkFromLocation que, a continuación, utiliza el pasado CLLocation a través de reverseGeocodeLocation para establecer el CLPlacemark? que serán devueltos.

Estoy teniendo problemas con la creación de la completionHandler cierre en reverseGeocodeLocation, es tirar un error de compilador/crash:

De Swift, CLGeocodeCompletionHandler es CLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Void de acuerdo a la documentación AnyObject[]! se supone que contienen CLPlacemark objetos como el Objetivo-C versión.

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?
}

EDIT: parece Que el error que tenía que hacer con placemarks.count con placemarks no ser tratado como una matriz. Compila ahora, sin embargo, estoy consiguiendo nada pero nil al intentar establecer p dentro de la completionHandler. He comprobado el CLLocations que se pasa y que son válidos.

EDIT 2: Después de la impresión placemarks, puedo confirmar que devuelve datos. Sin embargo p es todavía devolver nil.

InformationsquelleAutor AaronDancer | 2014-06-21

6 Kommentare

  1. 23

    He encontrado la respuesta que yo necesitaba en este hilo: Conjunto de cadena de dirección con reverseGeocodeLocation: y de retorno del método

    El problema recae en el hecho de que reverseGeocodeLocation es asincrónico, el método devuelve un valor antes de la completionBlock conjuntos de p en mi ejemplo.


    Conforme a 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) }
        })
    }

    Yo no quería tomar la NSNotificationCenter ruta ya que se agregue trabajo innecesario, en lugar de en el interior de la completionHandler cierre hago un llamado a otra función y pasar el CLPlacemark generado por getPlacemarkFromLocation como un parámetro para mantener las cosas asincrónica ya que la función se llamará después de placemarks se establece la función (debe) recibir la marca de posición necesarios y ejecutar el código que desee. La esperanza de lo que he dicho tiene sentido.

    • ¿Puede explicar cómo has resuelto el problema? He tratado de funciones externas y las notificaciones y todavía estoy recibiendo EXC_BAD_ACCESS. Gracias de antemano, esto ayudaría a otros desarrolladores de la transición a Swift.
    • lo siento, yo estaba usando esta sintaxis… self!.geocoder.reverseGeocodeLocation(location, completionHandler:{ [weak self] (placemarks: [AnyObject]!, error: NSError!) -> Void in // Your code here. })
    • Seguro, voy a editar este post y añadir mi código actual y elaborar un poco más.
  2. 15

    Con estas líneas de Swift, usted puede imprimir completamente la ubicación de la direcció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)
            }
        })
    }

    Saludos!

  3. 3

    Aquí es el cierre que trabajó para mí-tomó un tiempo para llegar a trabajar. Yo creo que tu problema está relacionado con no inicializar p con la correcta inicialización. He intentado un par de variaciones, hasta que llegué a este trabajo: auto.marca de posición = CLPlacemark(marca: cosas[0] como 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
            }
    
            })

    EDICIÓN:

    movido mejor respuesta a su propia respuesta.

    • Parece como p no se inicializa es el problema, así que he cambiado p = placemarks[0] as? CLPlacemark a p = CLPlacemark(placemark: placemarks[0] as? CLPlacemark) sin embargo p todavía devuelve nil. Traté de inicializar p antes de reverseGeocodeLocation se llama, sin embargo puedo obtener EXC_BAD_ACCESS cuando se intenta cambiar el valor. No puedo utilizar la CLPlacemark(placemark: CLPlacemark?) inicializador de antemano porque no tengo CLPlacemark a dar
  4. 0

    EDIT: Esto no funciona. El valor es nulo fuera de la clausura — ver los comentarios de abajo

    Su p es nula, porque el cierre es la captura antes de que se inicializa a una referencia. Para obtener el comportamiento que usted desea que usted necesita para hacer que el p no opcional como valor de var p : CLPlacemark!.

    A continuación es el código que he utilizado para poner a prueba mis conjeturas:

     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í es de registro de la consola:

    Pushit <- presiona el botón para iniciar la ubicación de la captura

    Fuera de lo que es en p: vacío

    Dentro de lo que es en p: Estados unidos

    Fuera de lo que es en p: vacío

    Dentro de lo que es en p: Estados unidos

    Fuera de lo que es en p: vacío…

    • He intentado que así, sin embargo yo obtener EXC_BAD_ACCESS a la hora de hacerlo.
    • Yo lo he probado de nuevo, estoy consiguiendo el mismo resultado que en el ejemplo anterior, cuando el uso de un no-valor opcional.
    • Cierres para swift no parecen funcionar como cabría esperar. La única manera de conseguir el interior valor de «palo» fuera de la clausura es si la marca fue una variable miembro de la controladora. Probablemente sería trabajar con static/variables de clase si swift compatibles (aparentemente no disponible en la versión beta). Nota, incluso traté de usar un array local inicializado fuera de la clausura. He añadido (anexa) la marca de posición en la matriz en el cierre. Pero fuera de el cierre de la matriz se siguen empleando.
    • Aarón, su solución a continuación se hace perfecto sentido. Buen trabajo. Fue divertido engañando con esto he aprendido mucho acerca de Swift cierres. Me gustaría comentar en la respuesta pertinente si estaba habilitado para… 🙂
    • Como de la Beta 3, tipos de matrices se escriben ahora con los corchetes el tipo de elemento de… Cambio: let pm = placemarks as? CLPlacemark[] a: let pm = placemarks as? [CLPlacemark]
    • Yep. Notó que el día de ayer. Bastante extraño. Voy a hacer una edición

  5. 0

    Poco tarde para este partido, pero parece que tú necesitas(ed) para hacer algo de terreno leyendo acerca de async cosas. Diciendo que, usted probablemente ha aprendido por ahora.

    El problema básico con el código es que p (su posición) se establece después de la función devuelve, así que se perdió – usted no puede utilizar una función para devolver un valor con async. Con la finalización de cierre, el código se pasa la marca de posición cuando llega (asincrónicamente) & el cierre se invoca – nota la función regresa ahora 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)
        })
    }

    Uso –

    getPlacemarkFromLocation(myLocation, completion: { (placemark) in
        //do something with the placemark here
    })

    Que en realidad no he puesto esto en Xcode, pero se ve a la derecha…

  6. -3

    Tus cosas no funciona para un número de razones. Aquí está la parte que me fijo, sin realmente mirar 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
    }
    • Esto devuelve nil – no eres consciente de que p se establece después de devolver el valor, como reverseGeocodeLocation obras async

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea