1

I am trying to show a table view which shows institutions by car travel times.

  1. The query loops through a list of schools in the database to retrieve their coordinates
  2. Calculate the distance from the user's current location
  3. If the distance is less than 20 miles, calculate the eta time using MKDirections()
  4. Once the eta times have been calculated, append the relevant information to the table view's array, sort the array by eta times and only keep the top 10

The issue here is, there are often many institutions within 20 miles of the user's current location and MKDirections() limits the amount of requests you can make to calculate eta times in a given timeframe. So, quite often my table view is unable to show the eta times.

The obvious solution for me is to sort and trim the array before I calculate the eta times (thus avoiding the too many calculate eta requests issue).

What I tried:

  1. Append the data inside the for loop to 'Array1'
  2. Sort and trim Array1
  3. Outside/after the for loop, I loop through Array1 to calculate eta times and then append this data to Array2 which will be the array that feeds the tableview

I found that this doesn't work because the code outside/after the for loop is executed before the for loop is finished.

            let schoolDB = Database.database().reference().child("Schools")
            schoolDB.observe(.value, with: { (snapshot) in
                self.subjectTimesArray.removeAll()
                for child in snapshot.children {
                    let schoolSnapshot = child as! DataSnapshot
                    let approvalString = schoolSnapshot.childSnapshot(forPath: "Approved").value as! String
                    if approvalString == "Yes" {
                        let schoolID = schoolSnapshot.key
                        let schoolName = schoolSnapshot.childSnapshot(forPath: "Name").value as! String
                        let schoolLatitude = schoolSnapshot.childSnapshot(forPath: "Latitude").value as! Double
                        let schoolLongitude = schoolSnapshot.childSnapshot(forPath: "Longitude").value as! Double
                        let schoolLocation = CLLocation(latitude: schoolLatitude, longitude: schoolLongitude)
                        let distance = schoolLocation.distance(from: self.userLocation) / 1600
                        
                        if distance < 20 {
                            let subjectDB = Database.database().reference().child("Subject/" + schoolID + "/" + date)
                            subjectDB.observeSingleEvent(of: .value, with: { (subjectSnapshot) in
                                let startTime = subjectSnapshot.childSnapshot(forPath: "Maths/Start").value as! String
                                    
                                let userPlacemark = MKMapItem(placemark: MKPlacemark(coordinate: userLocation.coordinate))
                                let schoolPlacemark = MKMapItem(placemark: MKPlacemark(coordinate: schoolLocation.coordinate))
                                let directionsRequest = MKDirections.Request()
                                directionsRequest.source = userPlacemark
                                directionsRequest.destination = schoolPlacemark
                                directionsRequest.requestsAlternateRoutes = false
                                directionsRequest.transportType = .automobile
                                    
                                let directions = MKDirections(request: directionsRequest)
                                directions.calculateETA(completionHandler: { (response, error) in
                                    if let seconds = response?.expectedTravelTime {
                                        let minutes = seconds / 60    
                                        self.subjectTimesArray.append(.init(schoolID: schoolID, schoolName: schoolName, distance: distance, eta: Int(minutes), subjectStart: startTime))
                                    }
                                    
                                    self.subjectTimesArray.sort(by: {$0.eta < $1.eta})
                                    if self.subjectTimesArray.count > 10 {
                                            self.subjectTimesArray.removeLast(self.subjectTimesArray.count - 10)
                                    }
                                    self.subjectTimesTableView.reloadData()
                                })
                            })
                        }
                    }
                }
            })
Raf A
  • 179
  • 1
  • 12

1 Answers1

1

You can make a function that calculates the distance with a parameter as the school and call it when the distance is less than 20 miles, or append each school in the database to a new array if its under 20 miles and calculate off that array. If you do the second option it would only be looping through schools that are under 20 miles, I would recommend the first option.

Lucas Dahl
  • 722
  • 1
  • 5
  • 20