Swift – CLGeocoder reverseGeocodeLocation completionHandler闭包

我要做的是将CLLocation传递给函数getPlacemarkFromLocation ,然后通过reverseGeocodeLocation使用传递的CLLocation来设置CLPlacemark? 将被退回。

我在reverseGeocodeLocation创建completionHandler闭包时reverseGeocodeLocation reverseGeocodeLocation 了编译器错误/崩溃:

在Swift中, CLGeocodeCompletionHandlerCLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Void根据文档AnyObject[]! 应该像Objective-C版本一样包含CLPlacemark对象。

这是我目前的代码:

 class func getPlacemarkFromLocation(location:CLLocation)->CLPlacemark?{ var g = CLGeocoder() var p:CLPlacemark? g.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in let pm = placemarks as? CLPlacemark[] if (pm && pm?.count > 0){ p = placemarks[0] as? CLPlacemark } }) return p? } 

编辑:似乎错误与placemarks.countplacemarks不被视为数组。 它现在编译,但是当我尝试在completionHandler设置p时,我只得到nil。 我已经检查了传递的CLLocation并且它们是有效的。

编辑2:打印placemarks ,我可以确认它返回数据。 然而, p仍然没有返回。

我在这个post中找到了我需要的答案: 使用reverseGeocodeLocation设置地址字符串:并从方法返回

问题在于reverseGeocodeLocation是异步的,该方法在我的示例中在completionBlock设置p之前返回一个值。

根据要求,这是我目前的代码。

 func showAddViewController(placemark:CLPlacemark){ self.performSegueWithIdentifier("add", sender: placemark) } func getPlacemarkFromLocation(location: CLLocation){ CLGeocoder().reverseGeocodeLocation(location, completionHandler: {(placemarks, error) in if error {println("reverse geodcode fail: \(error.localizedDescription)")} let pm = placemarks as [CLPlacemark] if pm.count > 0 { self.showAddPinViewController(placemarks[0] as CLPlacemark) } }) } 

我不想采用NSNotificationCenter路由,因为这会增加不必要的开销,而是在completionHandler闭包内我调用另一个函数并将CLPlacemark生成的getPlacemarkFromLocation作为参数传递以保持异步,因为在getPlacemarkFromLocation之后将调用函数设置函数(应该)接收所需的地标并执行您想要的代码。 希望我所说的有道理。

使用Swift的这些行,您可以完全打印出该位置的地址:

 func getLocationAddress(location:CLLocation) { var geocoder = CLGeocoder() println("-> Finding user address...") geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error)->Void in var placemark:CLPlacemark! if error == nil && placemarks.count > 0 { placemark = placemarks[0] as CLPlacemark var addressString : String = "" if placemark.ISOcountryCode == "TW" /*Address Format in Chinese*/ { if placemark.country != nil { addressString = placemark.country } if placemark.subAdministrativeArea != nil { addressString = addressString + placemark.subAdministrativeArea + ", " } if placemark.postalCode != nil { addressString = addressString + placemark.postalCode + " " } if placemark.locality != nil { addressString = addressString + placemark.locality } if placemark.thoroughfare != nil { addressString = addressString + placemark.thoroughfare } if placemark.subThoroughfare != nil { addressString = addressString + placemark.subThoroughfare } } else { if placemark.subThoroughfare != nil { addressString = placemark.subThoroughfare + " " } if placemark.thoroughfare != nil { addressString = addressString + placemark.thoroughfare + ", " } if placemark.postalCode != nil { addressString = addressString + placemark.postalCode + " " } if placemark.locality != nil { addressString = addressString + placemark.locality + ", " } if placemark.administrativeArea != nil { addressString = addressString + placemark.administrativeArea + " " } if placemark.country != nil { addressString = addressString + placemark.country } } println(addressString) } }) } 

干杯!

这是关闭对我有用 – 它需要一段时间才能使它工作。 我认为你的问题与不使用正确的初始化程序初始化p有关。 我尝试了一些变化,直到我开始工作:self.placemark = CLPlacemark(placemark:stuff [0] as CLPlacemark)

 geocoder.reverseGeocodeLocation(newLocation, completionHandler: {(stuff, error)->Void in if error { println("reverse geodcode fail: \(error.localizedDescription)") return } if stuff.count > 0 { self.placemark = CLPlacemark(placemark: stuff[0] as CLPlacemark) self.addressLabel.text = String(format:"%@ %@\n%@ %@ %@\n%@", self.placemark.subThoroughfare ? self.placemark.subThoroughfare : "" , self.placemark.thoroughfare ? self.placemark.thoroughfare : "", self.placemark.locality ? self.placemark.locality : "", self.placemark.postalCode ? self.placemark.postalCode : "", self.placemark.administrativeArea ? self.placemark.administrativeArea : "", self.placemark.country ? self.placemark.country : "") } else { println("No Placemarks!") return } }) 

编辑:

更好地回答了自己的答案。

编辑:这不起作用。 关闭之外的值为零 – 请参阅下面的评论

你的p是nil,因为闭包在初始化为引用之前捕获它。 要获得所需的行为,您需要使用非可选值,例如var p:CLPlacemark!。

下面是我用来测试我的猜想的代码:

  func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) { var g = CLGeocoder() var p:CLPlacemark? let mynil = "empty" g.reverseGeocodeLocation(newLocation, completionHandler: { (placemarks, error) in let pm = placemarks as? CLPlacemark[] if (pm && pm?.count > 0){ // p = CLPlacemark() p = CLPlacemark(placemark: pm?[0] as CLPlacemark) println("Inside what is in p: \(p?.country ? p?.country : mynil)") } }) println("Outside what is in p: \(p?.country ? p?.country : mynil)") } 

这是控制台日志:

按下Pushit < - 按钮开始捕获位置
外面的东西是p:空的
在p:美国的内部
外面的东西是p:空的
在p:美国的内部
外面的东西是p:空…

这个派对迟到了,但看起来你需要(ed)做一些关于异步的东西。 这么说,你现在可能已经学会了。

你的代码的基本问题是在函数返回后正在设置p(你的地标),所以它只是丢失了 – 你不能使用函数来返回带异步的值。 使用完成闭包,代码在到达时(异步)传递地标并调用闭包 – 注意函数现在什么都不返回。

 func getPlacemarkFromLocation(_ location: CLLocation, completion: ((CLPlacemark?) -> ())) { CLGeocoder().reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in // use optional chaining to safely return a value or nil // also using .first rather than checking the count & getting placemarks[0] - // if the count is zero, will just give you nil // probably a good idea to check for errors too completion(placemarks?.first) }) } 

使用 –

 getPlacemarkFromLocation(myLocation, completion: { (placemark) in // do something with the placemark here }) 

我实际上并没有把它放到Xcode中,但看起来不错……

由于种种原因,你的东西不起作用。 这是我在没有实际查看function的情况下修复的部分:

 class func getPlacemarkFromLocation(location:CLLocation)->CLPlacemark?{ var g = CLGeocoder() var p:CLPlacemark? g.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) in let pm = placemarks! if (pm.count > 0){ p = placemarks![0] } }) return p }