web-dev-qa-db-fra.com

Trouvez le nom de la ville et le pays à partir de la latitude et la longitude en Swift

Je travaille sur l'application dans Swift3 Et j'ai un problème de lettre je ne peux pas trouver la réponse. 

Comment savoir si les noms abrégés des villes et des pays sont basés sur la latitude et la longitude? 

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

Je recommanderais d'intégrer Google Maps API à votre projet. Si vous le faites, votre tâche peut être réalisée à l'aide de Reverse Geocoding Google fournit. 

De plus, il y a Google Maps SDK développement pour IOS, ce qui mérite également d'être pris en compte.

UPD: Vous pouvez le faire sans intégrer de cartes dans votre projet. En vous basant sur this answer, vous pouvez y parvenir en utilisant des requêtes http à l'API Google. La demande à:

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

renverrait JSON objet avec des informations sur le lieu demandé, y compris le nom du pays et de la ville.

En passant, je vous recommande vivement d'utiliser Alamofire pour faire des requêtes http dans Swift.

16
Nikitin Roman

Vous pouvez utiliser la méthode CLGeocoder reverseGeocodeLocation pour récupérer un CLPlacemark et obtenir les informations country et locality . Notez qu'il s'agit d'une méthode asynchrone, vous devrez donc ajouter un gestionnaire d'achèvement à votre méthode lors de l'extraction de ces informations:

import UIKit
import MapKit
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

func fetchCityAndCountry(from location: CLLocation, completion: @escaping (_ city: String?, _ country:  String?, _ error: Error?) -> ()) {
    CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in
        completion(placemarks?.first?.locality,
                   placemarks?.first?.country,
                   error)
    }
}

Usage

let location = CLLocation(latitude: -22.963451, longitude: -43.198242)

fetchCityAndCountry(from: location) { city, country, error in
    guard let city = city, let country = country, error == nil else { return }
    print(city + ", " + country)  // Rio de Janeiro, Brazil
}
14
Leo Dabus

Ce dont vous avez besoin s'appelle le géocodage inversé. Comme vous avez déjà déclaré certaines propriétés en haut. Vous devez ajouter le CLGeocoder & CLPlancemark

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?

Créer une fonction permettant de démarrer les services de localisation

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

créez également un autre pour arrêter une fois que vous avez terminé avec le géocodage d'emplacement

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

en vue didLoad ou de n'importe où vous voulez commencer le gestionnaire d'emplacement ajoutez un contrôle d'abord

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

}

implémenter les méthodes de délégation pour le gestionnaire d'emplacement 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()
}

implémenter la méthode déléguée pour le gestionnaire d'emplacement 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()

           })
    }
}

Ajouter la fonction 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
    }

}

Vous devez cmd + cliquer sur CLPlacemark pour voir toutes les propriétés auxquelles vous pouvez accéder, par exemple le nom de la rue est appelé voie de circulation & le numéro est appelé subThoroughfare continuez à lire la documentation pour plus d'informations

Remarque: vous devez vérifier les erreurs d'emplacement et d'erreur de géocodeur que je n'ai pas encore implémentées ici, mais vous devez prendre soin de ces erreurs et le meilleur endroit pour vérifier les codes d'erreur. Tout le reste est la documentation relative aux pommes.

Mise à jour : Vérifier la fonction paresPlacemarks où j'ai ajouté isoCountryCode, qui correspond à pays shortName. Inutile d'ajouter des appels réseau supplémentaires à Google API et à Alamofire lorsque vous utilisez déjà des services de localisation.

8
Khalid Afridi

Voici le code 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)
}
4
Mannam Brahmam

Vous pouvez utiliser CLGeocoder , à partir de CoreLocation, pour cela. De la documentation Apple (souligne le mien):

Objet mono-coup pour la conversion entre les coordonnées géographiques et les noms de lieux.

La classe CLGeocoder fournit des services de conversion entre une coordonnée (spécifiée en tant que latitude et longitude) et la représentation conviviale de cette coordonnée. Une représentation conviviale des coordonnées comprend généralement les informations de rue, ville, État et pays correspondant à l'emplacement donné ...

Ce service n'a aucun lien avec MapKit et, en tant que tel, ne nécessite pas que vous utilisiez/affichez une carte dans votre application.

3
Paulo Mattos

1 . importer CoreLocation 2. insérez CLLocationManagerDelegate dans votre classe 3. Faites les méthodes déléguées décrites ci-dessous ... espérons que cela vous aidera vous pouvez trouver le nom de la ville et le pays en suivant ces étapes ... Voici mon code 

importer UIKit

importer CoreLocation 

classe MyViewController: UIViewController, CLLocationManagerDelegate {

override func viewDidLoad() {
    super.viewDidLoad()


    self.locationManager.delegate = self
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
    self.locationManager.requestWhenInUseAuthorization()
    self.locationManager.requestAlwaysAuthorization()
    self.locationManager.startUpdatingLocation()

}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {



    if( CLLocationManager.authorizationStatus() == .authorizedWhenInUse ||
        CLLocationManager.authorizationStatus() ==  .authorizedAlways){

       if let currentLocation = locationManager.location
       {

       if NetworkFunctions.NetworkRechability()
       {

        getAddressFromLatLon(pdblLatitude: "\(Double((currentLocation.coordinate.latitude)))", withLongitude: "\(Double((currentLocation.coordinate.longitude)))")

        }

        }
    }



}

func getAddressFromLatLon(pdblLatitude: String, withLongitude pdblLongitude: String) {
    var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
    let lat: Double = Double("\(pdblLatitude)")!

    let lon: Double = Double("\(pdblLongitude)")!

    let ceo: CLGeocoder = CLGeocoder()
    center.latitude = lat
    center.longitude = lon

    let loc: CLLocation = CLLocation(latitude:center.latitude, longitude: center.longitude)


    ceo.reverseGeocodeLocation(loc, completionHandler:
        {(placemarks, error) in
            if (error != nil)
            {
            }

            if placemarks != nil
            {

                let pm = placemarks! as [CLPlacemark]

                if pm.count > 0 {

                    let pm = placemarks![0]

                    print(pm.country ?? "")
                    print(pm.locality ?? "")
                   print(pm.subLocality ?? "")
                   print(pm.thoroughfare ?? "")
                    print(pm.postalCode ?? "")
                    print(pm.subThoroughfare ?? "")
                    var addressString : String = ""
                    if pm.subLocality != nil {
                        addressString = addressString + pm.subLocality! + ", "
                    }
                    if pm.thoroughfare != nil {
                        addressString = addressString + pm.thoroughfare! + ", "
                    }
                    if pm.locality != nil {
                        addressString = addressString + pm.locality! + ", "
                        if pm.country != nil {
                            addressString = addressString + pm.country! + ", "
                            //uuuuu
                            if(location_city != pm.locality!.trimmingCharacters(in: .whitespaces))
                            {
                                location_city=pm.locality!.trimmingCharacters(in: .whitespaces)
                                  DispatchQueue.main.async{
                                self.GetBeeWatherDetails(district: pm.locality!, country: pm.country!)
                                }
                            }
                        }

                    }

                    if pm.postalCode != nil {
                        addressString = addressString + pm.postalCode! + " "
                    }

                }
            }
    })

}

}

1
Fansad PP

Voir ma réponse dans Swift 4.1 Xcode 9.4.1. Vous pouvez même obtenir les détails du nom du village. Obtenir le nom du lieu à partir de Latitude et Longitude sous iOS

0
iOS

Cette méthode vous donnera l'emplacement actuel, le nom de la ville, le nom du pays, etc.

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    let location: CLLocation = locations.last!
    print("Location: \(location)")

    let geocoder = CLGeocoder()
    geocoder.reverseGeocodeLocation(location) { (placemarks, error) in
        // Process Response
        if let error = error {
            print("Unable to Reverse Geocode Location (\(error))")
        } else {
            if let placemarks = placemarks, let placemark = placemarks.first {
                self.city = placemark.locality!

                //self.country = placemark.country!
            }
        }
    }

    let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
                                          longitude: location.coordinate.longitude,
                                          zoom: zoomLevel)

     self.locationv = CLLocation(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)

    if myView.isHidden {
        myView.isHidden = false
        myView.camera = camera
    } else {
        myView.animate(to: camera)
    }
}
0
akbar khan

J'ai également eu le même problème. Vous pouvez utiliser ce code.

func placePicker(_ viewController: GMSPlacePickerViewController, didPick place: GMSPlace) {

    viewController.dismiss(animated: true, completion: nil)
    let geoCoder = CLGeocoder()
    let location = CLLocation(latitude: place.coordinate.latitude, longitude: place.coordinate.longitude)
    geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in

        // Place details
        var placeMark: CLPlacemark!
        placeMark = placemarks?[0]

        // Address dictionary
        print(placeMark.addressDictionary as Any)
   // 

    print("Place name \(place.name)")
    print("Place address \(String(describing: place.formattedAddress))")
    print("Place attributions \(String(describing: place.attributions))")



})
}

J'espère que cela résoudra votre problème.

0
Ayush Dixit