Question

I have a search bar in my application that the user can type an address into, and it will come up with the geocoded result. The result updates as the user types, according to the following code:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    ...
    if (self.geocoder.geocoding) [self.geocoder cancelGeocode];
    [self.geocoder geocodeAddressString:searchText completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error != nil) {
            NSLog(@"ERROR during geocode: %@", error.description);
            return;
        }
        //update the view
    }];
}

This works for the first few characters the user enters into the search field. However, after the user types more characters repeatedly, the geocoder starts giving the following error (which I know means that there was a problem with the network):

ERROR during geocode: Error Domain=kCLErrorDomain Code=2 "The operation couldn’t be completed. (kCLErrorDomain error 2.)"

The geocoder does not work again until the entire ViewController is reloaded. Why could this be happening, and what can I do to resolve it?

Was it helpful?

Solution

I believe the reason is the following:
Apple's geocoder does not answer every request in the same way. Instead, the first requests from a certain device are answered quickly, but if the device has sent say 100 requests or more, the answers arrive slower and slower or requests are not answered at all, which might cause your error.
When you reload the view controller, this simply takes time, and the geocoding server is more willing to answer again. Essentially, you cannot do anything about it, since the geocoder sever wants to protect itself from being overloaded by requests from a single device. You simply had to limit the number of requests that you send there.
BTW: The docs say "you should not send more than one geocoding request per minute".

OTHER TIPS

Note that this same error is returned when the device is offline.

I had this problem while picking location for messenger application. My solution was to introduce delay of 3 seconds, after user stop panning map, before geocoder call. To ensure that user want exactly that location.

I was using 3 delegate methods

func mapView(_ mapView: GMSMapView, willMove gesture: Bool)

func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition)

func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition)

And I was calling the reverse geolocation API in each of the methods. I got triggered the error message.

The error mainly because you are requesting the reverse geolocation API multiple times and more frequently.

How?

-> When you are about to start dragging, the first delegate method fires

-> When I was dragging the view, the camera is being changed, so the second delegate method is being fired and requesting geolocation API

-> When the camera is idle, the third delegate method is fired.

For my case, I had to show the location data in a label, like Uber set on the map, and I analyzed I need the data actually when the camera position is idle. Like I want to get the data of 10KM distance place, do I need the intermediate 9KM data?

so I removed the geolocation call from the first and second delegate method and kept only in the 3rd one. I was setting Loading.. in the label when the delegate methods got fired.

Fetching data in the background thread, because I don't want to hang up the main thread for this.

Also kept a 1-second delay before fetching, just for keeping a separation between the 2 API calls.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top