使用异步方法关闭 (Swift 2.0)

Posted

技术标签:

【中文标题】使用异步方法关闭 (Swift 2.0)【英文标题】:Closure with asynchronous method (Swift 2.0) 【发布时间】:2016-02-12 19:28:35 【问题描述】:

我正在做一个计算 MapView 上各个坐标之间的 ETA 的项目。我使用异步方法calculateETAWithCompletionHandler 来获取两个坐标之间的ETA,因为calculateETAWithCompletionHandler 是异步的,所以我的代码不是线性的。

我需要我的代码是线性的,以便在 TableView 中显示正确的 ETA 信息,因此我尝试实现一个闭包以在异步调用中返回。但是,这仍然没有使我的代码线性化。以下是我目前所拥有的,

override func viewDidLoad() 
    var etaBetween1n2 = 0

    let point1 = MKPointAnnotaion()
    point1.coordinate = CLLocationCoordinate2D(latitude: 36.977317, longitude: -122.054255)
    point1.title = "Point 1"
    mapView.addAnnotation(point1)

    let point2 = MKPointAnnotaion()
    point2.coordinate = CLLocationCoordinate2D(latitude: 36.992781, longitude: -122.064729)
    point2.title = "Point 2"
    mapView.addAnnotation(point2)

    print("A")

    // Closure
    calculateETA(point1, destination: point2)  (eta: Int) -> Void in
        print("B")
        etaBetween1n2 = eta
    

    print("C")



// Calculates ETA between source and destination
// Makes calculateETAWithCompletionHandler call which is asynchronous
func calculateETA(source: MKPointAnnotation, destination: MKPointAnnotation, result: (eta: Int) -> Void) 
    var eta = 0

    let request = MKDirectionsRequest()
    let sourceItem = MKMapItem(placemark: MKPlacemark(coordinate: source.coordinate, addressDictionary: nil))
    request.source = sourceItem
    request.transportType = .Automobile

    let destinationItem = MKMapItem(placemark: MKPlacemark(coordinate: destination.coordinate, addressDictionary: nil))
    request.destination = destinationItem

    request.destination = destinationItem
    request.requestsAlternateRoutes = false
    let directions = MKDirections(request: request)

    directions.calculateETAWithCompletionHandler  (etaResponse, error) -> Void in
        if let error = error 
            print("Error while requesting ETA : \(error.localizedDescription)")
         else 
            eta = Int((etaResponse?.expectedTravelTime)!)
            result(eta: eta)
        
    


我希望闭包可以通过打印使我的代码线性化,

A
B
C

但它仍然会打印,

A
C
B

是我错误地实现了闭包还是闭包是错误的方法?

【问题讨论】:

理想情况下,您应该调用一个从闭包内部刷新视图的方法,例如 reloadData 或类似的东西。 【参考方案1】:

所以闭包是一个回调,这意味着它会在调用该函数后继续运行其余代码,然后一旦准备好,它将运行回调函数。

所以如果你想在它完成后做某事,那么你可以把它放在回调中,这样你就可以把 print("B")

如果你可以计算一些东西,你的代码不应该是线性的,因为它会冻结主线程并且屏幕会变得无响应,直到操作完成。

之后你想做什么?

【讨论】:

我明白了。我想要做的是计算各个点(不仅仅是两个)之间的 ETA,所以我实际上将我的闭包放在一个迭代点的 for 循环中(为了简单起见,我在这里只提到了两个),然后从最短的 ETA 中对点进行排序最长。我在关闭后调用了函数sortETAs(),但它们在sortETA() 中始终为0,现在我知道为什么了。 所以应该在回调结束时调用 sortETA。我还将在上面提供一些我将如何编写它的代码。 感谢您的帮助!我正在考虑将一个点列表传递给calculateETA,而不是一次一个,并返回一个 Ints 列表(用于列表中每个点的 ETA)。【参考方案2】:

如果你想让“C”出现在 B 之后,那么你必须在闭包中调用它:

print("A")
calculateETA(point1, destination: point2)  (eta: Int) -> Void in
    print("B")
    etaBetween1n2 = eta

    print("C")

如果“C”比简单的打印语句更复杂,我敢肯定。将其封装在一个函数中,并在闭包中调用该函数。

    doStepA()
    calculateETA(point1, destination: point2)  (eta: Int) -> Void in
        doStepB()
        etaBetween1n2 = eta

        doStepC()
    


func doStepA() 
    print("A")


func doStepB() 
    print("B")


func doStepC() 
    print("C")

【讨论】:

感谢您的帮助!我现在对闭包有了更好的理解。

以上是关于使用异步方法关闭 (Swift 2.0)的主要内容,如果未能解决你的问题,请参考以下文章

对 ASP.NET 2.0 网页进行单元测试的最佳方法是啥? [关闭]

所有实体框架方法都应该使用异步吗? [关闭]

将 Objective-C 方法转换为 Swift [关闭]

无法在 IOS Swift 中使用委托方法关闭侧边菜单

应用程序中的调用函数didbecomeactive - Swift 2.0

vantuidialog异步关闭如何校验