如何从此闭包中恢复数据?

时间:2017-01-29 18:46:11

标签: ios swift closures google-places-api

我刚接触到swift中的闭包,并想知道如何从闭包中取回我的注释。我知道,因为它是异步的,外部数组不会在正确的时间填满。

我应该使用类似完成处理程序的东西吗?我怎么做?这是什么最好的做法?具有回调的函数从didupdateLocation调用。

 fileprivate func getGooglePoisForCurrentLocation(centerLatitude: Double, centerLongitude: Double, delta: Double, count: Int) -> Array<GMAnnotation>
        {
            var annotations: [GMAnnotation] = []

            placesClient.currentPlace(callback: { (placeLikelihoods, error) -> Void in
                if let error = error {
                    print("Current Place error: \(error.localizedDescription)")
                    return
                }

                if let likelihoodList = placeLikelihoods {
                    for likelihood in likelihoodList.likelihoods {

                        let annotation = GMAnnotation()
                        let place = likelihood.place

                        annotation.location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)

                        annotations.append(annotation)
                    }


                }
            })

            return annotations;  ====> EMPTY

2 个答案:

答案 0 :(得分:3)

是的,您需要在函数中添加@escaping闭包。请记住,异步函数会改变应用程序的工作方式 - 例如,如果要在表视图中显示此数据,则需要调用tableView.reloadData()(或其中一种兄弟方法)来实际更新数据可用后的表格。这是带闭包的函数:

fileprivate func getGooglePoisForCurrentLocation(centerLatitude: Double, centerLongitude: Double, delta: Double, count: Int, closure: @escaping (Array<GMAnnotation>) -> Void) {
    var annotations: [GMAnnotation] = []

    placesClient.currentPlace(callback: { (placeLikelihoods, error) -> Void in
        if let likelihoodList = placeLikelihoods {
            for likelihood in likelihoodList.likelihoods {

                let annotation = GMAnnotation()
                let place = likelihood.place

                annotation.location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)

                annotations.append(annotation)
            }
            closure(annotations)
        }
    })
}

调用它时,更新表视图的数据源,然后重新加载表视图:

getGooglePoisForCurrentLocationclosure(closure: { (annotations) -> Void in
    tableViewDataSourceArray = annotations
    tableView.reloadData()
})

作为旁注,这个例子不是特别安全 - 没有错误检查,返回类型不是可选的 - 如果API调用失败,它可能会崩溃。这是相同函数的更强大版本,它处理错误和正确的返回类型:

enum PlacesResult {
    case success(Array<GMAnnotation>)
    case error(Error)
}

fileprivate func getGooglePoisForCurrentLocation(centerLatitude: Double, centerLongitude: Double, delta: Double, count: Int, closure: @escaping (PlacesResult) -> Void) {
    var annotations: [GMAnnotation] = []

    placesClient.currentPlace(callback: { (placeLikelihoods, error) -> Void in
        if let error = error {
            print("Current Place error: \(error.localizedDescription)")
            closure(PlacesResult.error(error))
        }
        if let likelihoodList = placeLikelihoods {
            for likelihood in likelihoodList.likelihoods {
                let annotation = GMAnnotation()
                let place = likelihood.place
                annotation.location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)
                annotations.append(annotation)
            }
            closure(PlacesResult.success(annotations))
        } else {
            closure(PlacesResult.error(Error()))
            // something else went wrong but we still want this to call the closure.
        }
    })
}

答案 1 :(得分:1)

嗯,currentPlace来电是异步的,因此您无法立即在getGooglePoisForCurrentLocation函数中返回任何内容。

可以做这样的事情,具体取决于你的需求:

  • 将注释存储在ViewController的私有实例变量中
  • 调用一些UI刷新代码(如tableView.reloadData或ViewController中的其他内容)来更新UI。请注意,必须在主线程中执行此类调用(您可以使用DispatchQueue.main.async来执行此操作)