emsqre
emsqre

Reputation: 3

Swift Completion Handler for Reverse Geocoding

I have been banging my head in order to figure out how to fix this piece of code. Basically I have a piece of code that takes a string cityName and stores the latitude and longitude of it in a global variable and call it in another function right after. Apparently because of asynchronous call, I am not able to do that and the value of longitude and latitude are nil.

func findCityCoordinates(cityName: String)  {
        var geocoder = CLGeocoder()

        geocoder.geocodeAddressString(cityName, completionHandler: {(placemarks: [AnyObject]!, error: NSError!) -> Void in
            if let placemark = placemarks?[0] as? CLPlacemark {

              self.cityLatitude = placemark.location.coordinate.latitude //Returns nil
              self.cityLongitude = placemark.location.coordinate.longitude //Returns nil
            }
        })
    }

I have also been trying to work around completion handler but I have no idea on how to implement it and call it in a function. I would appreciate some help.

Upvotes: 0

Views: 1932

Answers (3)

emsqre
emsqre

Reputation: 3

Well my brother helped me a little bit out on this, basically I wanted to run a completion block in the IBAction of the save button instead inside of the function findCityCoordinates:

 func findCityCoordinate(city: String, completionHandler: (coordinate: CLLocationCoordinate2D) -> ()) { 
      let geocoder = CLGeocoder() 
      geocoder.geocodeAddressString(city) { (placemarks: [AnyObject]!, error: NSError!) -> () in 
          if let placemark = placemarks[0] as? CLPlacemark { 
              let coordinate = placemark.location.coordinate 
              completionHandler(coordinate: coordinate) 
          } 
      } 
 }

And heres the function being called inside the saveButton action outlet:

 findCityCoordinates(searchBar.text) { (cityCoordinate: CLLocationCoordinate2D) -> () in
     self.queryForTable(cityCoordinate)
     // Force reload of table data
     self.myTableView.reloadData()
 }

Upvotes: 0

MirekE
MirekE

Reputation: 11555

...stores the latitude and longitude of it in a global variable and call it in another function right after

I suspect that the other function is using it before the geocoder completion block sets the values. Put the call to the other function to the completion block, if possible.

func findCityCoordinates(cityName: String)  {
    var geocoder = CLGeocoder()
    geocoder.geocodeAddressString(cityName, completionHandler: {(placemarks: [AnyObject]!, error: NSError!) -> Void in
        if let placemark = placemarks?[0] as? CLPlacemark {
            self.cityLatitude = placemark.location.coordinate.latitude //Returns nil
            self.cityLongitude = placemark.location.coordinate.longitude //Returns nil

            *** <-- call your function that uses location here --> ***
        }
    })
}

Upvotes: 0

Caleb
Caleb

Reputation: 5616

I was able to use the dispatch async for this. I declared two variables above the geocoder, assign them inside, and use them after it completes.

var lat:Float!
var long:Float!
let geocoder = CLGeocoder()
geocoder.geocodeAddressString(cityName, completionHandler: {(placemarks: [AnyObject]!, error: NSError!) -> Void in
    if let placemark = placemarks?[0] as? CLPlacemark {
         lat = Float(placemark.location.coordinate.latitude)
         long = Float(placemark.location.coordinate.longitude)
     }
     dispatch_async(
         dispatch_get_main_queue(), {
            self.cityLatitude = lat 
            self.cityLongitude = long 
      })
})

Upvotes: 1

Related Questions