I can't return latitude and longitude. I always get a 0.0 and 0.0.
What can I do to get these values?
Code :
func forwardGeocoding (address: String) -> (Double, Double) {
let geoCoder = CLGeocoder()
var latitude: Double = 0.0
var longitude: Double = 0.0
geoCoder.geocodeAddressString(address) { (placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if error != nil {
print(error?.localizedDescription)
} else {
if placemarks!.count > 0 {
let placemark = placemarks![0] as CLPlacemark
let location = placemark.location
latitude = Double((location?.coordinate.latitude)!)
longitude = Double((location?.coordinate.longitude)!)
print("before : \(latitude, longitude)")
}
}
}
print("after : \(latitude, longitude)")
return (latitude, longitude)
}
This my viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
forwardGeocoding("New York, NY, United States")
}
Result:
after : (0.0, 0.0)
before : (40.713054, -74.007228)
It's quite obvious that your function returns always (0.0, 0.0). It's because geoCoder.geocodeAddressString()
returns placemarks asynchronously. It's time-consuming operation so you have to modify your code to handle that.
One of possible solutions is to modify your function:
func forwardGeocoding (address: String, completion: (Bool, CLLocationCoordinate2D!) -> () ) {
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(address) { (placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if error != nil {
print(error?.localizedDescription)
completion(false,nil)
} else {
if placemarks!.count > 0 {
let placemark = placemarks![0] as CLPlacemark
let location = placemark.location
completion(true, location?.coordinate)
}
}
}
And call it:
self.forwardGeocoding(YourAdress, completion {
success, coordinate in
if success {
let lat = coordinate.lattitude
let long = coordinate.longitude
// Do sth with your coordinates
} else {
// error sth went wrong
}
}
Notice that your function returns nothing. Hope that helps.
The problem with your code is that geocoding requests are asynchronous, so the return
statement is executed before the geocoding results are actually retrieved.
I'd probably use one of two options to fix this. First, instead of returning a tuple, make your own completion handler, and call it after the placemark is found:
func forwardGeocoding (address: String, completion: (CLLocationCoordinate2D) -> Void) {
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(address) { (placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if error != nil {
print(error?.localizedDescription)
} else {
if placemarks!.count > 0 {
let placemark = placemarks![0] as CLPlacemark
let location = placemark.location
completion(location.coordinate)
}
}
}
}
Now when you call this function you can provide the completion with the relevant values from wherever you're calling the function.
If the function is actually a method in a class and it never needs to be called from another class, you could have it set properties of the class, and those properties could have didSet
blocks. For example:
class SomeClass {
var coordinates: CLLocationCoordinate2D {
didSet {
doSomethingWithCoordinates()
}
}
private func forwardGeocoding (address: String, completion: (CLLocationCoordinate2D) -> Void) {
let geoCoder = CLGeocoder()
geoCoder.geocodeAddressString(address) { (placemarks: [CLPlacemark]?, error: NSError?) -> Void in
if error != nil {
print(error?.localizedDescription)
} else {
if placemarks!.count > 0 {
let placemark = placemarks![0] as CLPlacemark
let location = placemark.location
self.coordinates = location.coordinate
}
}
}
}
}
The first options is probably more versatile, but the second avoids having completion blocks withing completion blocks, which can sometimes become confusing to keep track of in your code.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.