如何获得连续的 MKDirection 请求响应 Swift
How to get sequential MKDirection requests responses Swift
我有一个将 [CLLocation]
作为输入的函数。在 while
循环中,它把它分成块,每个块发出一个 MKDirection
请求,将响应存储在一个新的 [CLLocation]
中,一旦完成就 returns 它。
问题是新数组中的所有块都不是顺序的,所以生成的路由到处都是。我如何在发出新请求之前等待以前的请求得到响应?我尝试了 DispatchQueue.global().sync
和 DispatchQueue.main.sync
,但没有任何区别。
我试图实现 的第一个答案,这似乎是我遇到的同样问题,但我不明白如何使它适应我的情况。
你能帮我按顺序得到回复吗?
这是函数,注释掉的部分是路由的最后一点,那将是最后一个请求。
一如既往,非常感谢您的帮助和时间。
func repositionLocation2(route: [CLLocation], completion: @escaping ([CLLocation]) -> Void) {
let group = DispatchGroup()
var pos = 0
var nextPos = 3
var repositioned = [CLLocation]()
// repositioned.append(route.first!)
guard route.count > nextPos else {print("Reposision Location failed, not enough positions");return}
let request = MKDirections.Request()
request.requestsAlternateRoutes = false
request.transportType = .walking
while pos < route.count - nextPos {
print(" pos in \(pos)")
// repositioned.removeAll()
group.enter()
// get a small chunk of the input route
let a = route[pos].coordinate//repositioned.last!.coordinate//
let b = route[pos + nextPos].coordinate
// get directions for the small chunk
request.source = MKMapItem(placemark: MKPlacemark(coordinate: a))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: b))
let directions = MKDirections(request: request)
// DispatchQueue.main.sync {
// DispatchQueue.global().sync {
// group.enter()
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)")
// save response coordinates into a new array
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
// group.leave()
}
// group.wait() // hangs the app
completion(repositioned)
}
// }
print("repositioned in while loop is : \(repositioned)")
// shift to nex addiacent chunk
pos += 3
nextPos += 3
}
// // last chunk
// let a = route[pos - 5].coordinate//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}
// 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)")
// repositioned.append(point)
// print("repositioned in for loop is : \(repositioned)")
// }
// completion(repositioned)
// }
// print("repositioned in while loop is : \(repositioned)")
}
当您有一系列异步任务(可能以任意顺序完成)并且您希望结果按顺序排列时,只需将其保存到一个顺序无关紧要的结构中,只需在最后对其进行排序.例如,您可以使用由整数索引索引的字典:
var routes: [Int: [CLLocationCoordinate2D]] = [:]
然后当任何给定的循环结束时,它可以只更新这个字典:
routes[i] = ...
如果你想在末尾排序平面数组:
let coordinates = steps.sorted { [=12=].0 < .0 }
.flatMap { [=12=].1 }
或者,您可以使用预填充的可选数组,您可以在数组中的正确位置插入特定路由:
var routes: [[CLLocationCoordinate2D]?] = Array(repeating: nil, count: pointCount - 1)
当你想更新一个时:
routes[i-1] = ...
然后,最后,您可以使用 compactMap
删除可选值并使用 flatMap
:
将其展平
let coordinates = steps.compactMap { [=15=] }.flatMap { [=15=] }
因此:
func fetchDirections(_ locations: [CLLocation], completion: @escaping ([CLLocationCoordinate2D]) -> Void) {
let pointCount = locations.count
guard pointCount > 1 else { return }
var routes: [[CLLocationCoordinate2D]?] = Array(repeating: nil, count: pointCount - 1)
let group = DispatchGroup()
for i in 1 ..< pointCount {
group.enter()
directions(from: locations[i-1], to: locations[i]).calculate { response, error in
defer { group.leave() }
guard
error == nil,
let response = response,
let route = response.routes.first
else { return }
routes[i-1] = self.coordinates(for: route.steps)
}
}
group.notify(queue: .main) {
let coordinates = routes.compactMap { [=16=] }.flatMap { [=16=] }
completion(coordinates)
}
}
func directions(from: CLLocation, to: CLLocation) -> MKDirections {
let request = MKDirections.Request()
request.source = MKMapItem(placemark: MKPlacemark(coordinate: from.coordinate))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: to.coordinate))
request.requestsAlternateRoutes = false
request.transportType = .walking
return MKDirections(request: request)
}
func coordinates(for steps: [MKRoute.Step]) -> [CLLocationCoordinate2D] {
guard !steps.isEmpty else { return [] }
var coordinates: [CLLocationCoordinate2D] = []
for step in steps {
let count = step.polyline.pointCount
let pointer = step.polyline.points()
for i in 0 ..< count {
let coordinate = pointer[i].coordinate
if coordinate.latitude != coordinates.last?.latitude, coordinate.longitude != coordinates.last?.longitude {
coordinates.append(coordinate)
}
}
}
return coordinates
}
其中:
fetchDirections(locations) { coordinates in
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
self.mapView.addOverlay(polyline)
}
让步,逛苹果综合大楼:
顺便说一下,请注意我不只是使用 MKRoute.Step
的 polyline
的 coordinate
。那是折线的中心。您可能想遍历 points()
.
话虽这么说,但我在获取路线时,一般只是在地图上显示而已,所以我一般只是直接将polyline
添加为叠加层,而不必费心将其分解为CLLocationCoordinate2D
的数组,但我假设您还有其他原因想要这样做。
我有一个将 [CLLocation]
作为输入的函数。在 while
循环中,它把它分成块,每个块发出一个 MKDirection
请求,将响应存储在一个新的 [CLLocation]
中,一旦完成就 returns 它。
问题是新数组中的所有块都不是顺序的,所以生成的路由到处都是。我如何在发出新请求之前等待以前的请求得到响应?我尝试了 DispatchQueue.global().sync
和 DispatchQueue.main.sync
,但没有任何区别。
我试图实现
func repositionLocation2(route: [CLLocation], completion: @escaping ([CLLocation]) -> Void) {
let group = DispatchGroup()
var pos = 0
var nextPos = 3
var repositioned = [CLLocation]()
// repositioned.append(route.first!)
guard route.count > nextPos else {print("Reposision Location failed, not enough positions");return}
let request = MKDirections.Request()
request.requestsAlternateRoutes = false
request.transportType = .walking
while pos < route.count - nextPos {
print(" pos in \(pos)")
// repositioned.removeAll()
group.enter()
// get a small chunk of the input route
let a = route[pos].coordinate//repositioned.last!.coordinate//
let b = route[pos + nextPos].coordinate
// get directions for the small chunk
request.source = MKMapItem(placemark: MKPlacemark(coordinate: a))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: b))
let directions = MKDirections(request: request)
// DispatchQueue.main.sync {
// DispatchQueue.global().sync {
// group.enter()
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)")
// save response coordinates into a new array
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
// group.leave()
}
// group.wait() // hangs the app
completion(repositioned)
}
// }
print("repositioned in while loop is : \(repositioned)")
// shift to nex addiacent chunk
pos += 3
nextPos += 3
}
// // last chunk
// let a = route[pos - 5].coordinate//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}
// 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)")
// repositioned.append(point)
// print("repositioned in for loop is : \(repositioned)")
// }
// completion(repositioned)
// }
// print("repositioned in while loop is : \(repositioned)")
}
当您有一系列异步任务(可能以任意顺序完成)并且您希望结果按顺序排列时,只需将其保存到一个顺序无关紧要的结构中,只需在最后对其进行排序.例如,您可以使用由整数索引索引的字典:
var routes: [Int: [CLLocationCoordinate2D]] = [:]
然后当任何给定的循环结束时,它可以只更新这个字典:
routes[i] = ...
如果你想在末尾排序平面数组:
let coordinates = steps.sorted { [=12=].0 < .0 }
.flatMap { [=12=].1 }
或者,您可以使用预填充的可选数组,您可以在数组中的正确位置插入特定路由:
var routes: [[CLLocationCoordinate2D]?] = Array(repeating: nil, count: pointCount - 1)
当你想更新一个时:
routes[i-1] = ...
然后,最后,您可以使用 compactMap
删除可选值并使用 flatMap
:
let coordinates = steps.compactMap { [=15=] }.flatMap { [=15=] }
因此:
func fetchDirections(_ locations: [CLLocation], completion: @escaping ([CLLocationCoordinate2D]) -> Void) {
let pointCount = locations.count
guard pointCount > 1 else { return }
var routes: [[CLLocationCoordinate2D]?] = Array(repeating: nil, count: pointCount - 1)
let group = DispatchGroup()
for i in 1 ..< pointCount {
group.enter()
directions(from: locations[i-1], to: locations[i]).calculate { response, error in
defer { group.leave() }
guard
error == nil,
let response = response,
let route = response.routes.first
else { return }
routes[i-1] = self.coordinates(for: route.steps)
}
}
group.notify(queue: .main) {
let coordinates = routes.compactMap { [=16=] }.flatMap { [=16=] }
completion(coordinates)
}
}
func directions(from: CLLocation, to: CLLocation) -> MKDirections {
let request = MKDirections.Request()
request.source = MKMapItem(placemark: MKPlacemark(coordinate: from.coordinate))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: to.coordinate))
request.requestsAlternateRoutes = false
request.transportType = .walking
return MKDirections(request: request)
}
func coordinates(for steps: [MKRoute.Step]) -> [CLLocationCoordinate2D] {
guard !steps.isEmpty else { return [] }
var coordinates: [CLLocationCoordinate2D] = []
for step in steps {
let count = step.polyline.pointCount
let pointer = step.polyline.points()
for i in 0 ..< count {
let coordinate = pointer[i].coordinate
if coordinate.latitude != coordinates.last?.latitude, coordinate.longitude != coordinates.last?.longitude {
coordinates.append(coordinate)
}
}
}
return coordinates
}
其中:
fetchDirections(locations) { coordinates in
let polyline = MKPolyline(coordinates: coordinates, count: coordinates.count)
self.mapView.addOverlay(polyline)
}
让步,逛苹果综合大楼:
顺便说一下,请注意我不只是使用 MKRoute.Step
的 polyline
的 coordinate
。那是折线的中心。您可能想遍历 points()
.
话虽这么说,但我在获取路线时,一般只是在地图上显示而已,所以我一般只是直接将polyline
添加为叠加层,而不必费心将其分解为CLLocationCoordinate2D
的数组,但我假设您还有其他原因想要这样做。