функция, возвращающая массив, не получает добавления внутри цикла for Swift
Я новичок в запросе маршрутов и следуя статье hackingwithswift (https://www.hackingwithswift.com/example-code/location/how-to-find-directions-using-mkmapview-and-mkdirectionsrequest), я могу получить альтернативный маршрут к маршруту, который я только что отследил, при отслеживании нового. Моя цель - ввести[CLLocation]
получить маршрут от MKDirection
. Проблема в том, что при его отслеживании я получаю альтернативный маршрут, но при запросе его из сохраненного маршрута (того же, что я только что отслеживал), я получаю нольresponse
с сообщением об ошибке:
ошибка направления: Error Domain=MKErrorDomain Code=1 "Индикация, не доступная" UserInfo={NSLocalizedFailureReason=Le informazioni sull'itinerario non sono attualmente disponibili., MKErrorGEOError=-12, MKErrorGEOErrorUserbug = "NSLocalizedFailureInfo ="; }, MKDirectionsErrorCode=3, NSLocalizedDescription=Indicazioni stradali non disponibili}
Маршрут такой же, поэтому начало и конец идентичны. Вы видите, что я здесь делаю не так? Как всегда, большое спасибо.
func repositionLocation(route: [CLLocation]) -> [CLLocation] {
var repositioned: [CLLocation] = []
let request = MKDirections.Request()
request.requestsAlternateRoutes = false
request.transportType = .walking
let directions = MKDirections(request: request)
let a = route.first?.coordinate
let b = route.last?.coordinate
print("a is: \(String(describing: a)), b is \(String(describing: b))") // prints correct CLLocationCoordinate2D
request.source = MKMapItem(placemark: MKPlacemark(coordinate: a!))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: b!))
directions.calculate { [unowned self] response, error in
if let err = error {
print("direction error : \(err)")
}
guard let unwrappedResponse = response else {print("no suggested routes available"); return } // here always returns
guard let coord = unwrappedResponse.routes.first?.steps else {return}
for location in coord {
let point: CLLocation = CLLocation(latitude: location.polyline.coordinate.latitude, longitude: location.polyline.coordinate.longitude)
repositioned.append(point)
}
}
return repositioned
}
Обновить:
Я сужаю проблему: либо я делаю слишком много запросов (но делаю только один), и серверы перестают отвечать, либо, поскольку ответ асинхронный, функция завершается до того, как она действительно может получить действительный ответ, поскольку я вызывая его из TableView. Как бы я дождался ответа вcellForRow
?
Обновление 2:
После ценных предложений он теперь запрашивает маршрут и получает ответы, из которых я создаю новый CLLocation
для каждого шага и добавьте его в repositioned
массив, который возвращается по завершении. Я действительно вижу, что новыйCLLocation
правильно создается внутри for
пока я его распечатываю, размер массива не увеличивается, а в возвращаемом массиве будет только первое добавление из входного маршрута.
Более новая версия функции:
func repositionLocation(route: [CLLocation], completion: @escaping ([CLLocation]) -> Void) {
var pos = 0
var repositioned = [CLLocation]()
repositioned.append(route.first!)
guard route.count > 4 else {print("Reposision Location failed, not enough positions");return}
let request = MKDirections.Request()
request.requestsAlternateRoutes = false
request.transportType = .walking
while pos < route.count - 4 {
let a = repositioned.last!.coordinate
let b = route[pos + 4].coordinate
request.source = MKMapItem(placemark: MKPlacemark(coordinate: a))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: b))
let directions = MKDirections(request: request)
directions.calculate { [unowned self] response, error in
if let err = error {
print("direction error : \(err)")
}
guard let unwrappedResponse = response else {print("no suggested routes available"); return }
print("Response is: \(unwrappedResponse.debugDescription)")
guard let coord = unwrappedResponse.routes.first?.steps else {print("No coordinates");return}
print("coord is: \(coord)")
for location in coord {
let point: CLLocation = CLLocation(latitude: location.polyline.coordinate.latitude, longitude: location.polyline.coordinate.longitude)
print("point is: \(point)") // prints a correct CLLocation with coordinates
repositioned.append(point)
print("repositioned in for loop is : \(repositioned)") // prints just first appended location CLLocation with coordinates
}
}
print("repositioned in while loop is : \(repositioned)")
pos += 5
}
// last segment.
// let a = repositioned.last?.coordinate
// let b = route.last?.coordinate
//
// request.source = MKMapItem(placemark: MKPlacemark(coordinate: a!))
// request.destination = MKMapItem(placemark: MKPlacemark(coordinate: b!))
//
// let directions = MKDirections(request: request)
//
// directions.calculate { [unowned self] response, error in
// if let err = error {
// print("direction error : \(err)")
// }
// guard let unwrappedResponse = response else {print("no suggested routes available"); return }
// print("Response is: \(unwrappedResponse.debugDescription)")
// guard let coord = unwrappedResponse.routes.first?.steps else {print("No coordinates");return}
// for location in coord {
// let point: CLLocation = CLLocation(latitude: location.polyline.coordinate.latitude, longitude: location.polyline.coordinate.longitude)
// repositioned.append(point)
// }
print("repositioned at completion is : \(repositioned)")
completion(repositioned)
// }
}
Не смотрите на закомментированную часть, которая позаботится о последнем бите входного маршрута, который превышает часть, о которой заботятся внутри while
петля.
1 ответ
Есть несколько проблем:
Во-первых, вы пытаетесь построить пешеходный маршрут через всю США - традиционными методами эту задачу не решить. Я рекомендую ставить координаты точек на более близком расстоянии. Я проверил ваш код в точках ближе, и маршрут появляется.
Во-вторых, вы можете использовать этот код:
func repositionLocation(route: [CLLocation], completion: @escaping ([CLLocation]) -> Void) {
var repositioned = [CLLocation]()
let request = MKDirections.Request()
request.requestsAlternateRoutes = false
request.transportType = .walking
let a = route.first?.coordinate
let b = route.last?.coordinate
request.source = MKMapItem(placemark: MKPlacemark(coordinate: a!))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: b!))
let directions = MKDirections(request: request)
print("a is: \(String(describing: a)), b is \(String(describing: b))") // prints correct CLLocationCoordinate2D
request.source = MKMapItem(placemark: MKPlacemark(coordinate: a!))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: b!))
directions.calculate { response, error in
if let err = error {
print("direction error : \(err)")
}
guard let unwrappedResponse = response else {print("no suggested routes available"); return } // here always returns
for route in unwrappedResponse.routes {
self.mapView.addOverlay(route.polyline)
self.mapView.setVisibleMapRect(route.polyline.boundingMapRect, animated: true)
}
guard let coord = unwrappedResponse.routes.first?.steps else {return}
for location in coord {
let point: CLLocation = CLLocation(latitude: location.polyline.coordinate.latitude, longitude: location.polyline.coordinate.longitude)
repositioned.append(point)
}
completion(repositioned)
}
}
Ты устанавливаешь let directions = MKDirections(request: request)
, но только потом настроить request.source
а также request.destination
. В остальном результат получается асинхронно, поэтому я добавилcompletion
за результат.
Для тестирования вы можете позвонить так:
repositionLocation(route: [CLLocation(latitude: 40.7127, longitude: -74.0059), CLLocation(latitude: 40.79, longitude: -74.011)]) { result in
print(result)
}
UPD2:
@Vincenzo, как я вижу, вы неправильно используете обработчик завершения для закрытия, я бы рекомендовал вообще прочитать об асинхронности и закрытии.
Я рекомендую использовать этот код:
func repositionLocation(route: [CLLocation], completion: @escaping ([CLLocation]) -> Void) {
var pos = 0
var repositioned = [CLLocation]()
repositioned.append(route.first!)
guard route.count > 4 else {print("Reposision Location failed, not enough positions");return}
let request = MKDirections.Request()
request.requestsAlternateRoutes = false
request.transportType = .walking
while pos < route.count - 4 {
let a = repositioned.last!.coordinate
let b = route[pos + 4].coordinate
request.source = MKMapItem(placemark: MKPlacemark(coordinate: a))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: b))
let directions = MKDirections(request: request)
directions.calculate { [unowned self] response, error in
if let err = error {
print("direction error : \(err)")
}
guard let unwrappedResponse = response else {print("no suggested routes available"); return }
print("Response is: \(unwrappedResponse.debugDescription)")
guard let coord = unwrappedResponse.routes.first?.steps else {print("No coordinates");return}
print("coord is: \(coord)")
for location in coord {
let point: CLLocation = CLLocation(latitude: location.polyline.coordinate.latitude, longitude: location.polyline.coordinate.longitude)
print("point is: \(point)") // prints a correct CLLocation with coordinates
repositioned.append(point)
print("repositioned in for loop is : \(repositioned)") // prints just first appended location CLLocation with coordinates
}
completion(repositioned)
}
print("repositioned in while loop is : \(repositioned)")
pos += 5
}
}