不能等待 MKDirections.calculate 的结果,取而代之的是 nil

Posted

技术标签:

【中文标题】不能等待 MKDirections.calculate 的结果,取而代之的是 nil【英文标题】:Cannot wait for the result of MKDirections.calculate, getting nil instead of it 【发布时间】:2018-08-28 14:09:16 【问题描述】:

我想使用MKDirections.calculate 计算我当前位置与CLLocations 列表之间的实际步行距离。但是,由于某种原因,函数末尾的 return 命令不等待结果,而是尝试返回空变量。我的代码如下所示:

func getDistance (location1: CLLocation, location2: CLLocation) 
    let coordinates1 = location1.coordinate
    let placemark1 = MKPlacemark(coordinate: coordinates1)
    let sourceItem = MKMapItem(placemark: placemark1)
    let coordinates2 = location2.coordinate
    let placemark2 = MKPlacemark(coordinate: coordinates2)
    let destinationItem = MKMapItem(placemark: placemark2)

    let request = MKDirectionsRequest()
    request.source = sourceItem
    request.destination = destinationItem
    request.requestsAlternateRoutes = true
    request.transportType = .walking

    var distance: Double?

    let directions = MKDirections(request: request)
    directions.calculate  (response, error) in

        if var routeResponse = response?.routes 
            routeResponse.sort(by: $0.expectedTravelTime < $1.expectedTravelTime)
            let quickestRoute: MKRoute = routeResponse[0]
            distance = Double(quickestRoute.distance)
        
    

    return distance //returns nil

然后我想在这样的代码中使用该函数:

let myLocation = CLLocation(latitude: 47.0, longitude: 17.0)
let destinationArray = [CLLocation(latitude: 47.1, longitude: 17.1), CLLocation(latitude: 47.2, longitude: 17.2), CLLocation(latitude: 47.3, longitude: 17.3)]
var distanceArray: [Double] = []
for destination in destinationArray 
    distanceArray.append(getDistance(location1: myLocation, location2: destination))

return distanceArray

我尝试过闭包,但它们不起作用,因为我找不到返回 distanceArray 的方法(同样的错误,它没有等待闭包运行并返回空数组)。我也尝试过 DispatchGroups 但它们没有效果(也许我以错误的方式实现它们)。

非常感谢您的帮助。

谢谢。

【问题讨论】:

【参考方案1】:

使用 MapKit 和 Swift 5

计算两个位置位置之间的距离,它会帮助任何人

示例功能:我已经在 Google Map 和 Apple Map 中进行了测试

        let startLocation : CLLocation = CLLocation.init(latitude: 23.0952779, longitude: 72.5274129)
        let endLocation : CLLocation = CLLocation.init(latitude: 23.0981711, longitude: 72.5294229)
        let distance = startLocation.distance(from: endLocation)
        self.getDistance(departureDate: Date().adjust(hour: 8, minute: 0, second: 0, day: 0, month: 0), arrivalDate: Date().adjust(hour: 8, minute: 10, second: 0, day: 0, month: 0), startLocation: startLocation, endLocation: endLocation)  (distanceInMeters) in

            print("fake distance: \(distance)")
            let fakedistanceInMeter = Measurement(value: distance, unit: UnitLength.meters)
            let fakedistanceInKM = fakedistanceInMeter.converted(to: UnitLength.kilometers).value
            let fakedistanceInMiles = fakedistanceInMeter.converted(to: UnitLength.miles).value
            print("fakedistanceInKM :\(fakedistanceInKM)")
            print("fakedistanceInMiles :\(fakedistanceInMiles)")


            print("actualDistance : \(distanceInMeters)")

            let distanceInMeter = Measurement(value: distanceInMeters, unit: UnitLength.meters)
            let distanceInKM = distanceInMeter.converted(to: UnitLength.kilometers).value
            let distanceInMiles = distanceInMeter.converted(to: UnitLength.miles).value
            print("distanceInKM :\(distanceInKM)")
            print("distanceInMiles :\(distanceInMiles)")
        

函数的使用

                    self.getDistance(departureDate: trip.departure.dateTime, arrivalDate: trip.arrival.dateTime, startLocation: startLocation, endLocation: endLocation)  (actualDistance) in
                        print("actualDistance : \(actualDistance)")
                    

我对上面的功能进行了改进,在这里添加了代码,希望对大家有所帮助。

func calculateDistancefrom(departureDate: Date, arrivalDate: Date, sourceLocation: MKMapItem, destinationLocation: MKMapItem, doneSearching: @escaping (_ distance: CLLocationDistance) -> Void) 

        let request: MKDirections.Request = MKDirections.Request()

        request.departureDate = departureDate
        request.arrivalDate = arrivalDate

        request.source = sourceLocation
        request.destination = destinationLocation

        request.requestsAlternateRoutes = true
        request.transportType = .automobile

        let directions = MKDirections(request: request)
        directions.calculate  (directions, error) in
            if var routeResponse = directions?.routes 
                routeResponse.sort(by: $0.expectedTravelTime <
                    $1.expectedTravelTime)
                let quickestRouteForSegment: MKRoute = routeResponse[0]

                doneSearching(quickestRouteForSegment.distance)
            
        
    

    func getDistance(departureDate: Date, arrivalDate: Date, startLocation : CLLocation, endLocation : CLLocation, completionHandler: @escaping (_ distance: CLLocationDistance) -> Void) 

        let destinationItem =  MKMapItem(placemark: MKPlacemark(coordinate: startLocation.coordinate))
        let sourceItem      =  MKMapItem(placemark: MKPlacemark(coordinate: endLocation.coordinate))
        self.calculateDistancefrom(departureDate: departureDate, arrivalDate: arrivalDate, sourceLocation: sourceItem, destinationLocation: destinationItem, doneSearching:  distance in
            completionHandler(distance)
        )
    

【讨论】:

非常感谢!我会尽快尝试。 请接受答案并点赞。 @ViktorCsimma。祝你好运:-)【参考方案2】:

尝试以下闭包:

func getDistance (location1: CLLocation, location2: CLLocation,
    completion: @escaping(Double?) -> Void) 

    let coordinates1 = location1.coordinate
    let placemark1 = MKPlacemark(coordinate: coordinates1)
    let sourceItem = MKMapItem(placemark: placemark1)
    let coordinates2 = location2.coordinate
    let placemark2 = MKPlacemark(coordinate: coordinates2)
    let destinationItem = MKMapItem(placemark: placemark2)

    let request = MKDirectionsRequest()
    request.source = sourceItem
    request.destination = destinationItem
    request.requestsAlternateRoutes = true
    request.transportType = .walking

    var distance: Double?

    let directions = MKDirections(request: request)
    directions.calculate  (response, error) in

        if var routeResponse = response?.routes 
            routeResponse.sort(by: $0.expectedTravelTime < $1.expectedTravelTime)
            let quickestRoute: MKRoute = routeResponse[0]
            distance = Double(quickestRoute.distance)
            completion(distance)
        
    

用法:

    let myLocation = CLLocation(latitude: 47.0, longitude: 17.0)
    let destinationArray = [CLLocation(latitude: 47.1, longitude: 17.1), CLLocation(latitude: 47.2, longitude: 17.2), CLLocation(latitude: 47.3, longitude: 17.3)]
    var distanceArray: [Double] = []
    for destination in destinationArray 
        getDistance(location1: myLocation, location2: destination)  distance in
            print("distance", distance)
            if let distance = distance 
                distanceArray.append(distance)
            
        
    
    return distanceArray

【讨论】:

不幸的是,出现了类似的问题:它只返回 [ ]。你能帮帮我吗?【参考方案3】:

directions.calculate是一个异步函数,所以需要等待函数返回,才能返回计算出的距离。您应该使用完成处理程序来执行此操作……

func getDistance(location1: CLLocation, location2: CLLocation, completion: @escaping (Double) -> Void) 

    // etc 
    directions.calculate  (response, error) in

        if var routeResponse = response?.routes 
            routeResponse.sort(by: $0.expectedTravelTime < $1.expectedTravelTime)
            let quickestRoute: MKRoute = routeResponse[0]

            completion(Double(quickestRoute.distance))
        
    

然后你应该对你的距离数组做类似的事情。您需要等待所有 getDistance 调用返回,因此您可以使用 DispatchGroup...

func getDistanceArray(completion: @escaping ([Double]) -> Void) 

    let group = DispatchGroup()
    var distanceArray: [Double] = []

    for destination in destinationArray 
        group.enter()
        getDistance(location1: myLocation, location2: destination)  distance in
            distanceArray.append(distance)
            group.leave()
        
    
    group.wait()
    completion(distanceArray)

你可以调用...

getDistanceArray  distanceArray in
    print(distanceArray)

【讨论】:

请问,请问如何在此之后返回最终的distanceArray?我在那里遇到了同样的问题,它只返回空数组。谢谢。 更新了答案

以上是关于不能等待 MKDirections.calculate 的结果,取而代之的是 nil的主要内容,如果未能解决你的问题,请参考以下文章

python-asyncio TypeError:对象字典不能用于“等待”表达式

不能等待 MKDirections.calculate 的结果,取而代之的是 nil

在等待期望时使用 XCTFail 并不能防止超时

C# 为啥两个线程不能同时等待一个Mutex 释放

如何在“react-dropzone”的“onDrop”中使用异步等待? (解析错误:不能在异步函数之外使用关键字'await')

当我等待“reaction_remove”时,Bot.wait_for() 不能正常工作