5

I'm using Xcode 7 with iOS9. I want to sort a list ascending, based on distance from users current location to all other locations in the list.

I don't want to calculate the distance to a location by coordinates, but by address because the distance depends on the choosen method (drive / walk). All I want to do is save the address in each location object to calculate the distance to that object later on.

When initializing the list with objects I'm doing this request in each object's initializer:

let location = CLLocation(latitude: latitude, longitude: longitude) //changed!!!

CLGeocoder().reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in 
    //the code to obtain an address and save it in a location object is here and works
}

The problem I have now is that I have to send 172 such reverseGeocodeLocation requests as my list contains 172 objects and I need to calculate the distance from my users location to each object's location.

Sending so many requests so fast results in this error: The operation couldn’t be completed. (kCLErrorDomain error 2.)

Is there a way to solve this? If things aren't clear tell me please so I can clarify

2 Answers2

3

Apple's geocoding object is not intended for bulk-geocoding. See the CLGeocoder Class Reference in Xcode for more information. A brief excerpt:

Applications should be conscious of how they use geocoding. Geocoding requests are rate-limited for each app, so making too many requests in a short period of time may cause some of the requests to fail. (When the maximum rate is exceeded, the geocoder returns an error object with the value kCLErrorNetwork to the associated completion handler.) Here are some rules of thumb for using this class effectively:

Send at most one geocoding request for any one user action.

If the user performs multiple actions that involve geocoding the same location, reuse the results from the initial geocoding request instead of starting individual requests for each action.

When you want to update the user’s current location automatically (such as when the user is moving), issue new geocoding requests only when the user has moved a significant distance and after a reasonable amount of time has passed. For example, in a typical situation, you should not send more than one geocoding request per minute.

(Emphasis added by me.)

The summary is that you can't do what you are trying to do with Apple's CLGeocoder class.

You are only supposed to submit a single geocoding request for a user action, and then typically no more than one geocoding request per minute.

You'll need to license a third party geocoding service (and probably pay for it) in order to do bulk geocoding or reverse-geocoding.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Thanks, due to your response I used other keywords to search on my problem and found this question which mentions some API's for reverse-geocoding http://stackoverflow.com/questions/3513134/how-to-reverse-geocode-without-google – newbiedevelopper Dec 22 '15 at 16:39
1

I finally found the answer myself with help of some comments here.

At the moment, the only distance that can be retrieved using Apple Maps API is the straight line distance between coordinates. However if you want to calculate real distances between two addresses or coordinates you can do it with the Google Maps Distance Matrix API by sending a simple request.

Example:

Calculate the distance from: 51.226531,4.190688
to 51.114476,4.139618 and 51.148123,4.182590.

You can simply do this with this API call: https://maps.googleapis.com/maps/api/distancematrix/json?origins=51.226531,4.190688&destinations=51.114476,4.139618|51.148123,4.182590

Notice i'm using 3 parameters:
json: the format in which I want the result to be returned
origins: the coordinates/address where you start
destinations: multiple coordinates/addresses seperated by " | "

This is the result from the call:

{
  "destination_addresses" : [
  "Dorpstraat 70, 9140 Temse, België",
  "Eigenlostraat 38, 9100 Sint-Niklaas, België"
],
"origin_addresses" : [ "Provinciale Baan 37, 9120 Beveren, België" ],
"rows" : [
  {
     "elements" : [
        {
           "distance" : {
              "text" : "16,3 km",
              "value" : 16346
           },
           "duration" : {
              "text" : "22 min.",
              "value" : 1321
           },
           "status" : "OK"
        },
        {
           "distance" : {
              "text" : "10,5 km",
              "value" : 10521
           },
           "duration" : {
              "text" : "17 min.",
              "value" : 1003
           },
           "status" : "OK"
        }
     ]
  }
],
"status" : "OK" 
}

If things aren't clear, ask me!

Community
  • 1
  • 1
  • anyway there is not different than this "172 such reverseGeocodeLocation requests as my list contains 172 objects"..just you wont get the error but for client side you will be calling a lot API? – LC 웃 Dec 25 '15 at 11:37
  • that's what I thought at first as well but if you read the API well, you can retrieve multiple distances in one call by separating coordinates in the parameter with " | " – newbiedevelopper Dec 25 '15 at 14:13
  • oh thanks will look at it...can you throw the link ? – LC 웃 Dec 25 '15 at 17:22
  • 1
    @anishparajuli Google Distance Matrix API Documentation: https://developers.google.com/maps/documentation/distance-matrix/intro – newbiedevelopper Dec 26 '15 at 14:58
  • Keep in mind the maximum URL length when sending multiple requests at once. I doubt that 170 locations can be done with one request. – Darko Dec 26 '15 at 15:10
  • @Darko Well actually it can't because the URL length is more than 2000 with 170 locations, but I wrote some specific code so that it makes a request when a total length of 1800 is exceeded, so i got multiple requests and result but parsed them into one result afterwards – newbiedevelopper Dec 26 '15 at 15:20