What I'm trying to do is pass a CLLocation
to the function getPlacemarkFromLocation
which then uses the passed CLLocation
through reverseGeocodeLocation
to set the CLPlacemark?
that will be returned.
I'm having issues creating the completionHandler
closure in reverseGeocodeLocation
, it's throwing a compiler error/crash:
In Swift, CLGeocodeCompletionHandler
is CLGeocodeCompletionHandler = (AnyObject[]!, NSError!) -> Void
according to the documentation AnyObject[]!
is supposed to contain CLPlacemark
objects just like the Objective-C version.
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.count
with placemarks
not being treated like an array. It compiles now, however I'm getting nothing but nil when trying to set p
inside the completionHandler
. I've checked the CLLocation
s being passed and they are valid.
EDIT 2: After printing placemarks
, I can confirm that it returns data. However p
is still returning nil.
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.
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.
Use -
I've not actually put this into Xcode, but it looks right...
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)
EDIT:
moved better answer to its own answer.
With these lines of Swift, you can print out fully the location's address:
Cheers!
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!.
Below is code I used to test my conjecture:
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...
Your stuff doesn't work for a number of reasons. Here's the part that I fixed without actually looking at the functionality:
I found the answer I needed in this thread: Set address string with reverseGeocodeLocation: and return from method
The issue lies with the fact that
reverseGeocodeLocation
is asynchronous, the method is returning a value before the completionBlock setsp
in my example.As requested, here's my current code.
I didn't want to take the NSNotificationCenter route because that would add unnecessary overhead, rather inside the
completionHandler
closure I call upon another function and pass theCLPlacemark
generated bygetPlacemarkFromLocation
as a parameter to keep things asynchronous since the function will be called afterplacemarks
is set the function (should) receive the placemark needed and execute the code you want. Hope what I said makes sense.