简体   繁体   中英

iOS - How can I return latitude and longitude?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM