ios Swift - CLGeocoder reverseGeocodeLocation completionHandler 关闭

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24345296/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:02:29  来源:igfitidea点击:

Swift - CLGeocoder reverseGeocodeLocation completionHandler closure

iosswiftmapkitmkmapviewcllocation

提问by AaronDancer

What I'm trying to do is pass a CLLocationto the function getPlacemarkFromLocationwhich then uses the passed CLLocationthrough reverseGeocodeLocationto set the CLPlacemark?that will be returned.

我正在试图做的是传递CLLocation给函数getPlacemarkFromLocation,然后使用传递CLLocation通过reverseGeocodeLocation设置CLPlacemark?将返回。

I'm having issues creating the completionHandlerclosure in reverseGeocodeLocation, it's throwing a compiler error/crash:

我在创建completionHandler闭包时遇到问题reverseGeocodeLocation它引发了编译器错误/崩溃:



In Swift, CLGeocodeCompletionHandleris CLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Voidaccording to the documentation AnyObject[]!is supposed to contain CLPlacemarkobjects just like the Objective-C version.

在斯威夫特,CLGeocodeCompletionHandlerCLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Void根据文档AnyObject[]!应该包含CLPlacemark的对象,就像Objective-C的版本。

Here's my current code:

这是我当前的代码:

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?
}

EDIT: It seems like the error had to do with placemarks.countwith placemarksnot being treated like an array. It compiles now, however I'm getting nothing but nil when trying to set pinside the completionHandler. I've checked the CLLocations being passed and they are valid.

编辑:似乎错误placemarks.countplacemarks不被视为数组有关。它现在可以编译,但是当我尝试pcompletionHandler. 我检查了CLLocation正在通过的s 并且它们是有效的。

EDIT 2: After printing placemarks, I can confirm that it returns data. However pis still returning nil.

编辑 2:打印后placemarks,我可以确认它返回数据。但是p仍然返回零。

回答by AaronDancer

I found the answer I needed in this thread: Set address string with reverseGeocodeLocation: and return from method

我在这个线程中找到了我需要的答案:Set address string with reverseGeocodeLocation: and return from method

The issue lies with the fact that reverseGeocodeLocationis asynchronous, the method is returning a value before the completionBlock sets pin my example.

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


As requested, here's my current code.


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

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) }
    })
}

I didn't want to take the NSNotificationCenter route because that would add unnecessary overhead, rather inside the completionHandlerclosure I call upon another function and pass the CLPlacemarkgenerated by getPlacemarkFromLocationas a parameter to keep things asynchronous since the function will be called after placemarksis set the function (should) receive the placemark needed and execute the code you want. Hope what I said makes sense.

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

回答by Goon Nguyen

With these lines of Swift, you can print out fully the location's address:

使用 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)
        }
    })
}

Cheers!

干杯!

回答by JohnInSea

Here is closure that worked for me -- it took awhile to get it to work. I think your problem is related to not initializing p with the correct initializer. I tried a few variations until I got this to work: self.placemark = CLPlacemark(placemark: stuff[0] as CLPlacemark)

这是对我有用的闭包——它需要一段时间才能发挥作用。我认为您的问题与未使用正确的初始化程序初始化 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
        }

        })

EDIT:

编辑:

moved better answer to its own answer.

移动更好的答案到自己的答案。

回答by JohnInSea

EDIT: This doesn't work. The value is nil outside the closure -- see comments below

编辑:这不起作用。该值在闭包外为零 - 请参阅下面的评论

Your p is nil because the closure is capturing it before it is initialized to a reference. To get the behavior you want you need to make p a non-optional value such as var p : CLPlacemark!.

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

Below is code I used to test my conjecture:

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

 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)")

}

Here is console log:

这是控制台日志:

Pushit <- button pressed to start location capturing
Outside what is in p: empty
Inside what is in p: United States
Outside what is in p: empty
Inside what is in p: United States
Outside what is in p: empty...

Pushit <- 按下按钮开始位置捕捉
在 p 中之外:空 在 p 中
内部:美国 在 p 中
外部:空 在 p 中
内部:美国 在 p 中
外部:空...

回答by SomaMan

Bit late to this party, but it looks like you need(ed) to do some ground-up reading about async stuff. Saying that, you've probably learnt it by now.

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

The basic problem with your code is that p (your placemark) is being set after the function returns, so it's just lost - you can't use a function to return a value with async. With a completion closure, your code is passed the placemark when it arrives (asynchronously) & the closure is invoked - note the function is now returning nothing.

您的代码的基本问题是 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)
    })
}

Use -

用 -

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

I've not actually put this into Xcode, but it looks right...

我实际上并没有把它放到 Xcode 中,但它看起来是对的......

回答by Ryan Dines

Your stuff doesn't work for a number of reasons. Here's the part that I fixed without actually looking at the functionality:

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

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
}