38

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?

jburns20
  • 3,147
  • 2
  • 26
  • 32

4 Answers4

71

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".

Reinhard Männer
  • 14,022
  • 5
  • 54
  • 116
  • Oh yeah, I didn't notice that line in the docs. Makes perfect sense. – jburns20 Jul 25 '13 at 20:40
  • 2
    Sure wish there was a grace period of a week or two while developing : ( – Gabriel Jensen Feb 21 '17 at 22:13
  • You can actually wait a couple of seconds after this error then try again and it works perfectly fine – Kode Sep 08 '18 at 21:29
  • How long do you have to wait until this error goes away? My test device has been returning this error for days now. – hotdogsoup.nl Aug 16 '19 at 08:03
  • I am sorry, I can't remember. What I do remember is that I could send about 30 requests very fast, and received an answer immediately, before the response stopped for a while. But it stopped only for something like half a minute. Maybe the server enforces this 1/sec on average... – Reinhard Männer Aug 16 '19 at 08:08
  • How to add a delay then? – user6539552 Mar 04 '21 at 15:48
  • Well, I did this 7 years ago, and maybe the server characteristics have changed since then. But I remember that that the first 30 (or so) requests were answered very quickly, but then you had to wait some time (maybe 20 sec?) before the next requests were answered successfully. I guess, you simply have to try it out. – Reinhard Männer Mar 04 '21 at 15:53
5

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

Vladimir Grigorov
  • 10,903
  • 8
  • 60
  • 70
  • 1
    That's all I knew about this error and getting it when _online_ threw me off so badly :/ –  Feb 20 '19 at 02:51
2

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.

slobodans
  • 859
  • 1
  • 17
  • 23
0

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.

Ankur Lahiry
  • 2,253
  • 1
  • 15
  • 25