1

[CLLocation]我有一个以 a作为输入的函数。在while循环内部,它将它分成块,对于每个块发出MKDirection请求,将响应存储在一个新的中[CLLocation],并在完成后返回它。

问题是新数组中的所有块都不是连续的,因此生成的路由会到处跳转。如何在创建新请求之前等待上一个请求得到响应?我试过了DispatchQueue.global().syncDispatchQueue.main.sync但这并没有什么不同。我试图从无法等待 MKDirections.calculate 的结果中实现第一个答案,得到 nil 而不是它,这似乎是我同样的问题,但我不明白如何使其适应我的情况。你能帮我按顺序得到回复吗?这是函数,注释掉的部分是路由的最新位,这将是最后一个请求。一如既往地感谢您的帮助和时间。

    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)")

    }
4

1 回答 1

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. 那是折线的中心。您大概想遍历.polylineMKRoute.Steppoints()

话虽如此,当我获得路线时,通常只是在地图上显示它,所以我通常只是polyline直接CLLocationCoordinate2D将想要这样做的原因。

于 2019-12-21T21:17:12.647 回答