如何获得顺序 MKDirection 请求响应 Swift
Posted
技术标签:
【中文标题】如何获得顺序 MKDirection 请求响应 Swift【英文标题】:How to get sequential MKDirection requests responses Swift 【发布时间】:2019-12-21 18:49:05 【问题描述】:我有一个将[CLLocation]
作为输入的函数。在while
循环中,它将其拆分为多个块,对于每个块发出一个MKDirection
请求,将响应存储在一个新的[CLLocation]
中并在完成后返回它。
问题是新数组中的所有块都不是连续的,所以生成的路由会到处跳转。如何在创建新请求之前等待上一个请求得到响应?我尝试了DispatchQueue.global().sync
和DispatchQueue.main.sync
,但这并没有什么不同。
我试图从Cannot wait for the result of MKDirections.calculate, getting nil instead of it 实现第一个答案,这似乎是我同样的问题,但我不明白如何适应我的情况。
你能帮我按顺序得到回复吗?
这是函数,注释掉的部分是路由的最新位,这将是最后一个请求。
一如既往,非常感谢您的帮助和时间。
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)")
【问题讨论】:
【参考方案1】:当您有一系列异步任务(可能以任意顺序完成)并且您希望结果按顺序排列时,只需将其保存到顺序无关紧要的结构中,只需在最后进行排序即可。例如,您可以使用由整数索引索引的字典:
var routes: [Int: [CLLocationCoordinate2D]] = [:]
然后当任何给定的循环结束时,它可以更新这个字典:
routes[i] = ...
如果你想要一个排序后的平面数组:
let coordinates = steps.sorted $0.0 < $1.0
.flatMap $0.1
或者,您可以使用预先填充的选项数组,您可以在数组中的正确位置插入特定路线:
var routes: [[CLLocationCoordinate2D]?] = Array(repeating: nil, count: pointCount - 1)
当你想更新一个时:
routes[i-1] = ...
然后,最后,您可以使用 compactMap
删除可选项并使用 flatMap
将其展平:
let coordinates = steps.compactMap $0 .flatMap $0
因此:
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 $0 .flatMap $0
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)
让步,在 Apple 的建筑群中漫步:
顺便说一句,请注意我不只是使用coordinate
和polyline
的MKRoute.Step
。那是折线的中心。您大概想遍历points()
。
话虽如此,当我获取路线时,通常只是在地图上显示它,所以我通常只是将polyline
直接添加为叠加层,而不是将其分解为@987654340的数组@,但我认为您有其他原因想要这样做。
【讨论】:
非常感谢所有的解释。我这样做的原因是 GPS 位置非常不精确,因此使用 GSP 跟踪路线会导致非常差的曲折跟踪。我使用的完整顺序是:第一个跟踪路线。 (非常疯狂的跟踪)第二次过滤掉低精度信号、非连续信号以及太远或太近的信号。 (好多了,但仍然是曲折的,点在任何地方都结束了......就像在建筑物的中间......)第三(使用这个功能)我有点将过滤后的路线捕捉到实际的步行路径...... 很难想象要获得正确的跟踪。我花了几个月的时间反复试验才想出这个解决方案,但它是我应用程序的基础,所以这是我今年能得到的最好的圣诞礼物。非常感谢,如果想出一个如此优雅的解决方案来捕捉道路部分,我会花费更长的时间。当然我可以使用谷歌地图功能.. 但我宁愿坚持使用 swift 的地图。最后,如果 Google 可以,我们也可以。 除了在您的示例中拱形左侧的几个侧面偏差之外,它工作得很好。我会尝试想出一个函数来清理它并称之为完成。我正在考虑在一个循环中检查 3 个点,如果 1 和 3 具有相同的坐标或在一个范围内,则排除 2。 FWIW,我的道路上的偏差是故意的。他们从健身中心走到迎宾中心,再到剧院,这意味着他们实际上是在原路返回。 我建议,如果您正在考虑丢弃或平滑哪些数据点,请考虑horizontalAccuracy
。您可能希望彻底消除因 GPS 数据不佳而导致的曲折,但不想消除用户实际走的弯路。以上是关于如何获得顺序 MKDirection 请求响应 Swift的主要内容,如果未能解决你的问题,请参考以下文章
如何最大限度地缩短响应时间,在客户端以极不同的速率发送请求的环境中最大化系统总体性能?
如何使用 system.io.pipes 发送请求并获得响应
如何等待http请求在处理到angular 7中的下一步之前获得响应[重复]