如何正确等待函数快速完成?

Posted

技术标签:

【中文标题】如何正确等待函数快速完成?【英文标题】:How to properly wait until function has finished doing in swift? 【发布时间】:2019-03-18 19:59:19 【问题描述】:

我现在尝试了很多东西,但似乎都没有。

我有一个 for 循环,它解析一些数据并将坐标转换为 ZIP 字符串:

for i in 0 ... results.count - 1

    result = results[i]
    self.coordinateToString(lat: result.lat, long: result.long, completion:  (place) in
                        someCell.label.text = place
                    )


func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) 
    let geoCoder = CLGeocoder()
    let location = CLLocation(latitude: lat, longitude: long)
    var ret = ""

    geoCoder.reverseGeocodeLocation(location, completionHandler:
    
        placemarks, error -> Void in

        guard let placeMark = placemarks?.first else  return 

        if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
        
            let toAppend = "\(zip)" + " \(town)"
            ret = toAppend

        
    )

    DispatchQueue.main.async 
        completion(ret)
    

但是我从来没有设法在单元格中显示正确的位置,它总是显示空白空间,因为它不等待完成处理程序完成转换。我在这里做错了什么?

【问题讨论】:

你在错误的地方拨打了DispatchQueue.main.async completion(ret) 哇,请阅读一些关于如何编码的快速约定,这是不可读的 【参考方案1】:

发生这种情况是因为reverseGeocodeLocation 立即返回并且其完成处理程序随后运行。这意味着ret 值在放入主队列时可能为空。您应该从回调中分派到 main,如下所示:

func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) 
  let geoCoder = CLGeocoder()
  let location = CLLocation(latitude: lat, longitude: long)
  var ret = ""

  geoCoder.reverseGeocodeLocation(location, completionHandler:
  
    placemarks, error -> Void in

    guard let placeMark = placemarks?.first else  return 

    if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
    
        let toAppend = "\(zip)" + " \(town)"
        ret = toAppend
        DispatchQueue.main.async 
          completion(ret)
       
    
)

当然,在这种情况下,您需要相应地处理错误情况。更好的是,使用defer,这样无论发生什么都会调用完成:

func coordinateToString(lat: Double, long: Double, completion: @escaping (String) -> ()) 
  let geoCoder = CLGeocoder()
  let location = CLLocation(latitude: lat, longitude: long)
  var ret = ""

  geoCoder.reverseGeocodeLocation(location, completionHandler:
  
    defer 
       DispatchQueue.main.async 
          completion(ret)
       
     

    placemarks, error -> Void in

    guard let placeMark = placemarks?.first else  return 

    if let zip = placeMark.postalCode, let town = placeMark.subAdministrativeArea
    
        let toAppend = "\(zip)" + " \(town)"
        ret = toAppend
    
)

【讨论】:

以上是关于如何正确等待函数快速完成?的主要内容,如果未能解决你的问题,请参考以下文章

如何等待递归直到函数完成执行

在继续之前等待一个功能完成的正确方法?

如何在节点 js 中正确使用等待/异步与 for 循环

如何等待函数在javascript中完成?

让 Jquery 函数等待动画完成

如何让 Lambda 函数等待异步操作完成?