Google Maps iOS Reverse Geocoding
Asked Answered
O

3

7

I am having an issue with Google Maps Reverse Geocoding when it comes to setting a UILabel's text to the reverse geocoded address. The UILabel is in an XIB use as a custom infowindow. I have another custom infowindow for other data that is working correctly however, it appears that when I try to set the label's text within the reverse geocode callback / completion handler, it doesn't work. Here is the code I have so far and I have tried the code multiple ways, including assigning it to variables and I have not been able to get anything to work.

let infoWindow = NSBundle.mainBundle().loadNibNamed("InfoWindowCurrent", owner: self, options: nil)[0] as! InfoWindowCurrent
let geocoder = GMSGeocoder()
let coordinate = CLLocationCoordinate2DMake(Double(self.locLatitude)!, Double(self.locLongitude)!)

var currentAddress = String()

geocoder.reverseGeocodeCoordinate(coordinate) { response , error in
    if let address = response?.firstResult() {
        let lines = address.lines! as [String]

        currentAddress = lines.joinWithSeparator("\n")
    }
}

infoWindow.labelAddressStreet.text = currentAddress

return infoWindow

I have also tried this:

let infoWindow = NSBundle.mainBundle().loadNibNamed("InfoWindowCurrent", owner: self, options: nil)[0] as! InfoWindowCurrent
let geocoder = GMSGeocoder()
let coordinate = CLLocationCoordinate2DMake(Double(self.locLatitude)!, Double(self.locLongitude)!)

geocoder.reverseGeocodeCoordinate(coordinate) { response , error in
    if let address = response?.firstResult() {
        let lines = address.lines! as [String]

        infoWindow.labelAddressStreet.text = lines.joinWithSeparator("\n")
    }
}

return infoWindow

Everything is connected correctly because the following code works:

let infoWindow = NSBundle.mainBundle().loadNibNamed("InfoWindowCurrent", owner: self, options: nil)[0] as! InfoWindowCurrent
let geocoder = GMSGeocoder()
let coordinate = CLLocationCoordinate2DMake(Double(self.locLatitude)!, Double(self.locLongitude)!)

geocoder.reverseGeocodeCoordinate(coordinate) { response , error in
    if let address = response?.firstResult() {
        let lines = address.lines! as [String]
    }
}

infoWindow.labelAddressStreet.text = "Unable to reverse geocode location!"

return infoWindow

Any help is definitely appreciated!

Osmanli answered 19/9, 2016 at 6:19 Comment(0)
O
2

So, I ended up going another route. It's not pretty, but it works. Each GMSMarker has a "userData" attribute that can be used to pass data. What I did was moved the marker creation into the reverse geocode completion handler and assigned the address to the "userData" attribute. Then, when the user taps to show the current address, the reverse geocode is kicked off, the marker is created and placed on the map.

geocoder.reverseGeocodeCoordinate(position) { response, error in
    if let location = response?.firstResult() {
        let marker = GMSMarker(position: position)
        let lines = location.lines! as [String]

        marker.userData = lines.joined(separator: "\n")
        marker.title = lines.joined(separator: "\n")
        marker.infoWindowAnchor = CGPoint(x: 0.5, y: -0.25)
        marker.accessibilityLabel = "current"
        marker.map = self.mapView

        self.mapView.animate(toLocation: position)
        self.mapView.selectedMarker = marker
    }
}

And when the marker is selected, the label is set to the address as passed in the "userData" attribute:

let infoWindow = Bundle.main.loadNibNamed("InfoWindowCurrent", owner: self, options: nil)?[0] as! InfoWindowCurrent

infoWindow.labelAddress.text = marker.userData as? String

return infoWindow
Osmanli answered 22/9, 2016 at 2:29 Comment(0)
A
10

You are using a return out of the braces of the geocoding, for this reason the last code works. You should do something like this:

func getAddress(currentAdd : ( returnAddress :String)->Void){

    let infoWindow = NSBundle.mainBundle().loadNibNamed("InfoWindowCurrent", owner: self, options: nil)[0] as! InfoWindowCurrent
    let geocoder = GMSGeocoder()
    let coordinate = CLLocationCoordinate2DMake(Double(self.locLatitude)!,Double(self.locLongitude)!)


    var currentAddress = String()

    geocoder.reverseGeocodeCoordinate(coordinate) { response , error in
        if let address = response?.firstResult() {
            let lines = address.lines! as [String]

            currentAddress = lines.joinWithSeparator("\n")

            currentAdd(returnAddress: currentAddress)
        }
    }     
}

And call that function

  getAddress() { (returnAddress) in      

    print("\(returnAddress)")

    }
Arcadia answered 19/9, 2016 at 7:14 Comment(1)
Unfortunately this will not work either. The external function would have to take the coordinates in and essentially return the address. I modified what you provided as a starting to point to accept the coordinates however, when I call getAddress() it returns the address as expected but I still cannot set the UILabel text as the address in the infoWindow.Osmanli
O
2

So, I ended up going another route. It's not pretty, but it works. Each GMSMarker has a "userData" attribute that can be used to pass data. What I did was moved the marker creation into the reverse geocode completion handler and assigned the address to the "userData" attribute. Then, when the user taps to show the current address, the reverse geocode is kicked off, the marker is created and placed on the map.

geocoder.reverseGeocodeCoordinate(position) { response, error in
    if let location = response?.firstResult() {
        let marker = GMSMarker(position: position)
        let lines = location.lines! as [String]

        marker.userData = lines.joined(separator: "\n")
        marker.title = lines.joined(separator: "\n")
        marker.infoWindowAnchor = CGPoint(x: 0.5, y: -0.25)
        marker.accessibilityLabel = "current"
        marker.map = self.mapView

        self.mapView.animate(toLocation: position)
        self.mapView.selectedMarker = marker
    }
}

And when the marker is selected, the label is set to the address as passed in the "userData" attribute:

let infoWindow = Bundle.main.loadNibNamed("InfoWindowCurrent", owner: self, options: nil)?[0] as! InfoWindowCurrent

infoWindow.labelAddress.text = marker.userData as? String

return infoWindow
Osmanli answered 22/9, 2016 at 2:29 Comment(0)
B
1

The first response worked for me. As an alternative to

marker.title = lines.joined(separator: "\n")`

try this, it will give you the street address:

marker.title = response?.firstResult()?.thoroughfare
marker.snippet = response?.firstResult()?.locality

For the city, try

marker.snippet = response?.firstResult()?.locality
Birth answered 8/1, 2017 at 18:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.