I am making requests for distance calculation from my current location to campsite locations in an array countySites using the calculate() method of the MKDirections class in a for loop. When I have an array of length 47 campsites only some of the campsite distances are calculated, the remainder produce an error message suggesting too many requests are being made. I don't know how to check that the calculate() isn't too busy before I make a request in the for loop.

I have tried placing a while loop in the code to repeatedly check for a calculation still being processed using the isCalculating Bool property but it fails to stop the error messages.

            countySites = england.counties[selectedCounty!]!

            let sourcePlacemark = MKPlacemark(coordinate: currentCoordinate!)
            let request = MKDirections.Request()

            request.source = MKMapItem(placemark: sourcePlacemark)
            request.transportType = .automobile
            request.requestsAlternateRoutes = false
            let group = DispatchGroup()

            activityIndicator.startAnimating()

            // Step through sites one by one
            for siteIndex in 0..<countySites.count {

                var selectedSite = countySites[siteIndex]
                let destinationPlacemark = MKPlacemark(coordinate: selectedSite.locationCoordinate)

                request.destination = MKMapItem(placemark: destinationPlacemark)

                let distanceAndDirections = MKDirections(request: request)

                if currentCoordinate != nil {

                    group.enter()
                    distanceAndDirections.calculate { (response, error) in
                        if error == nil {

                            let distanceInMetres = response?.routes.first?.distance
                            let distanceInMiles = distanceInMetres! / 1610
                            let roundedDistanceInMiles = Int(distanceInMiles.rounded())
                            let distanceToSite = roundedDistanceInMiles

                            selectedSite.distance = distanceToSite
                            self.countySites[siteIndex] = selectedSite

                        } else {
                            print(error.debugDescription)                            
                        }
                        group.leave()
                    }

                }

            }

            group.notify(queue: .main) {

                self.countySites = self.sortByDistance(sites: self.countySites)

                self.tableView.reloadData()

                self.activityIndicator.stopAnimating()

            }
        }

    }
1

There are 1 best solutions below

2
On

Only one solution to this problem is Just keep an array of MKRoute and whenever you come across with new path just save into that array and use the same array to draw a path, Using this method you can save mapKit distance calls as well

Check the below snippet which worked for me

var distanceArray: [MKRoute]? // like this create an array inside the class

func drawPath(destination: CLLocationCoordinate2D, source: CLLocationCoordinate2D) {

   let sourcePlacemark = MKPlacemark(coordinate: source, addressDictionary: nil)
   let destinationPlacemark = MKPlacemark(coordinate: destination, addressDictionary: nil)
    
   let sourceMapItem = MKMapItem(placemark: sourcePlacemark)
   let destinationMapItem = MKMapItem(placemark: destinationPlacemark)
    
    
   let directionRequest = MKDirectionsRequest()
   directionRequest.source = sourceMapItem
   directionRequest.destination = destinationMapItem
   directionRequest.transportType = .walking

   let directions = MKDirections(request: directionRequest)
    if distanceArray.count > 0 {
       guard let route = distanceArray.first?.routes else {return}
         self.showPath(route: route)
    } else {
       directions.calculate { (response, error) -> Void in
           guard let response = response else {
              if let error = error {
                 print("Error YuluMapView: \(error)")
              }
              return
            }
           guard let route = response.routes.first else {return}
           distanceArray.append(route)
          self.showPath(route: route)
        }
    }

}

func showPath(route: MKRoute) {
    self.add((route.polyline), level: MKOverlayLevel.aboveRoads)
    
    let rect = route.polyline.boundingMapRect
    self.setVisibleMapRect(rect, edgePadding: defaultEdgeInsets, animated: true)
}

It worked for me 100% and hope you can use this logic to avoid this issue.