I have a locationManager function to grab the users current location and posting the name of the city and state. I have a print statement so I can check in my console if eve
I had the same problem and Rob's answer didn't do it for me.
When the location service first starts, the location is updated multiple times regardless of the distanceFilter.
You might still want the location to be updated and you don't want to lose the location accuracy(which is the whole point of updating location multiple times on start-up), so calling stopUpdatingLocation(or using a local variable) after the first geolocating call isn't the way to go either.
The most intuitive way is to wrap your geocode call in an @objc function and call the the function with a delay:
NSObject.cancelPreviousPerformRequests(withTarget: self)
perform(#selector(myGeocodeFunction(_:)), with: location, afterDelay: 0.5)
I'd first suggest a few things:
Call stopUpdatingLocation
before you perform reverseGeocodeLocation
.
You are calling stopUpdatingLocation
inside the reverseGeocodeLocation
completion handler closure. The problem is that this runs asynchronously, and thus didUpdateLocations
may receive additional location updates in the intervening period. And often, when you first start location services, you'll get a number of updates, often with increasing accuracy (e.g. horizontalAccuracy
values that are smaller and smaller). If you turn off location services before initiating asynchronous geocode request, you'll minimize this issue.
You can also add add a distanceFilter
in viewDidLoad
, which will minimize redundant calls to the delegate method:
locationManager.distanceFilter = 1000
You can use your own state variable that checks to see if the reverse geocode process has been initiated. For example:
private var didPerformGeocode = false
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// if we don't have a valid location, exit
guard let location = locations.first where location.horizontalAccuracy >= 0 else { return }
// or if we have already searched, return
guard !didPerformGeocode else { return }
// otherwise, update state variable, stop location services and start geocode
didPerformGeocode = true
locationManager.stopUpdatingLocation()
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
let placemark = placemarks?.first
// if there's an error or no placemark, then exit
guard error == nil && placemark != nil else {
print(error)
return
}
let city = placemark?.locality ?? ""
let state = placemark?.administrativeArea ?? ""
self.navigationBar.title = ("\(city), \(state)")
self.usersLocation = ("\(city), \(state)")
print(self.usersLocation)
self.refreshPosts()
}
}