【问题标题】:Get Data From Async Completion Handler从异步完成处理程序获取数据
【发布时间】:2017-02-14 21:46:22
【问题描述】:

尝试获取城市名称,同时具有纬度和经度。 在模型类 Location 中,我使用 CLGeocoder(CoreLocation 的一部分)附带的 reverseGeocodeLocation(location: , completionHandler: ) 函数。

func getLocationName() {

    let geoCoder = CLGeocoder()
    let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)

    geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in
        guard let addressDict = placemarks?[0].addressDictionary else {
            return
        }

        if let city = addressDict["City"] as? String {
            self.currentCity = city
            print(city)
        }
        if let zip = addressDict["ZIP"] as? String {
            print(zip)
        }
        if let country = addressDict["Country"] as? String {
            print(country)
        }
    })
}

但是,在ViewController 中,在运行getLocationName() 之后,location.currentCitynil,因为完成处理程序是异步的,并且尚未完成。

如何确保完成处理程序已完成运行,以便我可以访问 location.currentCity

【问题讨论】:

  • 只需访问location.currentCityin完成处理程序或向getLocationName()添加另一个完成处理程序以异步返回数据。
  • 您不必“确保完成处理程序已完成运行”,您只需在completionHandler 中使用location.currentCity 做任何您想做的事情
  • @vadian 我需要访问视图控制器中的“location.currentCity”(在 Location 类之外)以更新 UI。添加另一个完成处理程序会更好吗,所以我不在模型类中更新 UI?您能否提供一个示例代码应该如何实现新的完成处理程序?
  • @AndrewBrooke 但我想用 viewController 中的 location.currentCity 更新我的 UI,并且我在模型类“Location”中没有视图控制器的实例。我应该创建那个实例,这样我就可以在完成处理程序中的某个地方执行“vcInstance.updateUI(currentCity)”吗?

标签: swift asynchronous core-location


【解决方案1】:

在 getLocationName 中将闭包作为函数参数传递 您可以在 reverseGeocodeLocation 闭包内调用。

func updateLocation(currentCity : String) -> Void
{
  print(currentCity)
}

func getLocationName(callback : @escaping (String) -> Void)
{

  let geoCoder = CLGeocoder()
  let location = CLLocation(latitude: currentLatitude, longitude: currentLongitude)

  geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in
     guard let addressDict = placemarks?[0].addressDictionary else {
        return
     }


     if let city = addressDict["City"] as? String
     {
         self.currentCity = city
         callback(city)

         print(city)
      }
      if let zip = addressDict["ZIP"] as? String {
         print(zip)
      }
      if let country = addressDict["Country"] as? String {
        print(country)
      }
   })
 }

在您的视图控制器中...

getLocationName(callback: updateLocation)

【讨论】:

  • 不太明白回调里面是什么...但是你给了我一些想法:如何在回调中设置'currentCity'?我可以这样做,因为回调只会在完成处理程序之后实现。对吗?
  • 回调将在完成处理程序完成时调用。您可以在 updateLocation 函数中设置 currentCity ,参见我的示例,您可以在 ViewController 中添加该函数。
  • 出现一堆错误:在 'func getLocationName(callback: (location:CLLocation) )' - 无法创建带有元素标签的单元素元组。在“回调(位置)”上 - 无法调用非函数类型“CLLocation”的值,在“打印(location.currentCity)”上——“CLLocation”类型的值没有成员“currentCity”
  • 当我在视图控制器中调用“Location.sharedInstance.getLocationName(updateLocation)”时,现在“使用未解析的标识符“updateLocation”。
  • 您需要在 ViewController 或 Location 类中添加 updateLocation 函数。或者您可以使用任何其他名称。它将是 reverseGeocodeLocation 完成时将调用的函数。
【解决方案2】:

我将创建一个使用 location.currentCity 的函数,并从完成处理程序中调用此函数

所以如果你的代码看起来像:

func foo() {
    var location
    getLocationName()
    print(location.currentcity) // nil
}

改成:

func foo() {
    var location
    getLocationName()
}

func bar() {
    print(location.currentcity) // someplace
}

并从您的完成处理程序调用 bar()

【讨论】:

  • 谢谢,这也是评论者的建议。但是,bar() 位于另一个类中(在 ViewController 中)。我想更新 bar() 中的 UI。我应该在位置模型文件中创建一个 viewController 实例并在其上运行“updateUI()”吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-01-13
  • 2023-03-25
  • 2012-08-10
  • 1970-01-01
  • 1970-01-01
  • 2015-06-11
  • 2022-01-21
相关资源
最近更新 更多