在Swift中查找经纬度的城市名称和国家

我在Swift3上的应用程序工作,我有信函问题,我找不到答案。

如何根据经纬度知道城市名称和国家短名称?

import UIKit import CoreLocation class ViewController: UIViewController, CLLocationManagerDelegate{ let locationManager = CLLocationManager() var latitude: Double = 0 var longitude: Double = 0 override func viewDidLoad() { super.viewDidLoad() // For use when the app is open & in the background locationManager.requestAlwaysAuthorization() // For use when the app is open //locationManager.requestWhenInUseAuthorization() locationManager.delegate = self locationManager.startUpdatingLocation() if CLLocationManager.locationServicesEnabled() { locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.startUpdatingLocation() } } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { if let location = locations.first { print(location.coordinate) latitude = location.coordinate.latitude longitude = location.coordinate.longitude } } func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { if (status == CLAuthorizationStatus.denied){ showLocationDisabledpopUp() } } func showLocationDisabledpopUp() { let alertController = UIAlertController(title: "Background Location Access Disabled", message: "We need your location", preferredStyle: .alert) let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil) alertController.addAction(cancelAction) let openAction = UIAlertAction(title: "Open Setting", style: .default) { (action) in if let url = URL(string: UIApplicationOpenSettingsURLString){ UIApplication.shared.open(url, options: [:], completionHandler: nil) } } alertController.addAction(openAction) self.present(alertController, animated: true, completion: nil) } } 

我会build议将Google Maps API与您的项目集成。 如果这样做,则可以使用Google提供的反向地理编码来完成您的任务。

而且,Google还有Google Maps SDK for IOS开发,这也值得考虑。

UPD:你可以做到这一点,而无需将地图集成到您的项目。 基于这个答案,你可以实现对Google API使用http请求。 要求:

 https://maps.googleapis.com/maps/api/geocode/json?latlng=40.714224,-73.961452&key=API_KEY 

会返回JSON对象,包含所需地点的信息,包括国家和城市名称。

顺便说一句,我强烈build议使用Alamofire在Swift中进行http请求。

你需要的是称为反向地理编码。 因为你已经在顶部声明了一些属性。 您需要添加CLGeocoderCLPlancemark

 let locationManager = CLLocationManager() var location: CLLocation? let geocoder = CLGeocoder() var placemark: CLPlacemark? // here I am declaring the iVars for city and country to access them later var city: String? var country: String? var countryShortName: String? 

创build一个可以启动位置服务的function

 func startLocationManager() { // always good habit to check if locationServicesEnabled if CLLocationManager.locationServicesEnabled() { locationManager.delegate = self locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.startUpdatingLocation() } } 

当您完成位置地理编码后,还可以创build另一个

 func stopLocationManager() { locationManager.stopUpdatingLocation() locationManager.delegate = nil } 

在视图didLoad或从任何地方你想启动位置pipe理器首先添加一个检查

 override func viewDidLoad() { super.viewDidLoad() let authStatus = CLLocationManager.authorizationStatus() if authStatus == .notDetermined { locationManager.requestWhenInUseAuthorization() } if authStatus == .denied || authStatus == .restricted { // add any alert or inform the user to to enable location services } // here you can call the start location function startLocationManager() } 

实施位置pipe理器didFailedWithError的委托方法

 func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { // print the error to see what went wrong print("didFailwithError\(error)") // stop location manager if failed stopLocationManager() } 

为位置pipe理器didUpdateLocations实现委托方法

  func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { // if you need to get latest data you can get locations.last to check it if the device has been moved let latestLocation = locations.last! // here check if no need to continue just return still in the same place if latestLocation.horizontalAccuracy < 0 { return } // if it location is nil or it has been moved if location == nil || location!.horizontalAccuracy > lastLocation.horizontalAccuracy { location = lastLocation // stop location manager stopLocationManager() // Here is the place you want to start reverseGeocoding geocoder.reverseGeocodeLocation(lastLocation, completionHandler: { (placemarks, error) in // always good to check if no error // also we have to unwrap the placemark because it's optional // I have done all in a single if but you check them separately if error == nil, let placemark = placemarks, !placemark.isEmpty { self.placemark = placemark.last } // a new function where you start to parse placemarks to get the information you need self.parsePlacemarks() }) } } 

添加parsePlacemarks函数

 parsePlacemarks() { // here we check if location manager is not nil using a _ wild card if let _ = location { // unwrap the placemark if let placemark = placemark { // wow now you can get the city name. remember that apple refers to city name as locality not city // again we have to unwrap the locality remember optionalllls also some times there is no text so we check that it should not be empty if let city = placemark.locality, !city.isEmpty { // here you have the city name // assign city name to our iVar self.city = city } // the same story optionalllls also they are not empty if let country = placemark.country, !country.isEmpty { self.country = country } // get the country short name which is called isoCountryCode if let countryShortName = placemark.isoCountryCode, !countryShortName.isEmpty { self.countryShortName = countryShortName } } } else { // add some more check's if for some reason location manager is nil } } 

你必须cmd +点击CLPlacemark看到所有的属性,你可以访问例如街道名称通称&号码被称为subThoroughfare继续阅读文档的更多信息

注意:您必须检查位置错误也geocoder错误,我没有在这里实现,但你必须照顾这些错误,最好的地方来检查错误代码和其他一切是苹果文档

更新 :检查paresPlacemarks函数,我添加isoCountryCode是等于国家短名称不需要添加额外的networking调用谷歌API和Alamofire,而你已经使用的位置服务

您可以使用来自CoreLocation的CLGeocoder。 从苹果文档(强调我的):

用于在地理坐标和地名之间转换的单次拍摄对象。

CLGeocoder类提供了在坐标(指定为经度和纬度)和用户友好的坐标表示之间进行转换的服务。 用户友好的坐标表示通常由对应于给定位置的街道, 城市 ,州和国家信息组成。

这项服务与MapKit无关,因此,不需要在您的应用程序中使用/显示地图。

您可以使用CLGeocoder reverseGeocodeLocation方法来获取CLPlacemark并获取国家和地区属性信息。 请注意,这是一个asynchronous方法,因此您需要在获取该信息时向您的方法添加完成处理程序:

 func fetchCountryAndCity(location: CLLocation, completion: @escaping (String, String) -> ()) { CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in if let error = error { print(error) } else if let country = placemarks?.first?.country, let city = placemarks?.first?.locality { completion(country, city) } } } 

用法

 let location = CLLocation(latitude: -22.963451, longitude: -43.198242) fetchCountryAndCity(location: location) { country, city in print("country:", country) print("city:", city) } 

这是Swift 4代码:

  var locationManager = CLLocationManager() override func viewDidLoad() { super.viewDidLoad() locationManager.delegate = self locationManager.requestWhenInUseAuthorization() locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.startUpdatingLocation() locationManager.startMonitoringSignificantLocationChanges() // Here you can check whether you have allowed the permission or not. if CLLocationManager.locationServicesEnabled() { switch(CLLocationManager.authorizationStatus()) { case .authorizedAlways, .authorizedWhenInUse: print("Authorize.") let latitude: CLLocationDegrees = (locationManager.location?.coordinate.latitude)! let longitude: CLLocationDegrees = (locationManager.location?.coordinate.longitude)! let location = CLLocation(latitude: latitude, longitude: longitude) //changed!!! CLGeocoder().reverseGeocodeLocation(location, completionHandler: {(placemarks, error) -> Void in if error != nil { return }else if let country = placemarks?.first?.country, let city = placemarks?.first?.locality { print(country) self.cityNameStr = city } else { } }) break case .notDetermined: print("Not determined.") self.showAlertMessage(messageTitle: "Bolo Board", withMessage: "Location service is disabled!!") break case .restricted: print("Restricted.") self.showAlertMessage(messageTitle: "Bolo Board", withMessage: "Location service is disabled!!") break case .denied: print("Denied.") } } } func showAlertMessage(messageTitle: NSString, withMessage: NSString) ->Void { let alertController = UIAlertController(title: messageTitle as String, message: withMessage as String, preferredStyle: .alert) let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action:UIAlertAction!) in } alertController.addAction(cancelAction) let OKAction = UIAlertAction(title: "Settings", style: .default) { (action:UIAlertAction!) in if let url = URL(string: "App-Prefs:root=Privacy&path=LOCATION/com.company.AppName") { if #available(iOS 10.0, *) { UIApplication.shared.open(url, options: [:], completionHandler: nil) } else { // Fallback on earlier versions } } } alertController.addAction(OKAction) self.present(alertController, animated: true, completion:nil) }