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)
}
}
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.
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
}
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.
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)
}
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.
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! + " "
}
}
}
})
}
}
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
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)
}
}
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.