Swift - CLGeocoder reverseGeocodeLocation completionHandler closure
I found the answer I needed in this thread: Set address string with reverseGeocodeLocation: and return from method
The issue lies with the fact that reverseGeocodeLocation
is asynchronous, the method is returning a value before the completionBlock sets p
in my example.
As requested, here's my current code.
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) } })}
I didn't want to take the NSNotificationCenter route because that would add unnecessary overhead, rather inside the completionHandler
closure I call upon another function and pass the CLPlacemark
generated by getPlacemarkFromLocation
as a parameter to keep things asynchronous since the function will be called after placemarks
is set the function (should) receive the placemark needed and execute the code you want. Hope what I said makes sense.
With these lines of Swift, you can print out fully the location's address:
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) } })}
Cheers!
Here is closure that worked for me -- it took awhile to get it to work. I think your problem is related to not initializing p with the correct initializer. I tried a few variations until I got this to work: 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 } })
EDIT:
moved better answer to its own answer.