ios - geocoder - Convertir coordenadas al nombre de la ciudad?
geocoder swift (8)
¿Cómo obtener una dirección de coordenadas usando MapKit?
Tengo este código cuando presiono largo en el mapa obtiene las coordenadas:
func didLongPressMap(sender: UILongPressGestureRecognizer) {
if sender.state == UIGestureRecognizerState.Began {
let touchPoint = sender.locationInView(self.mapView)
let touchCoordinate = self.mapView.convertPoint(touchPoint, toCoordinateFromView: self.mapView)
var annotation = MKPointAnnotation()
annotation.coordinate = touchCoordinate
annotation.title = "Your position"
self.mapView.addAnnotation(annotation) //drops the pin
println("lat: /(touchCoordinate.latitude)")
var num = (touchCoordinate.latitude as NSNumber).floatValue
var formatter = NSNumberFormatter()
formatter.maximumFractionDigits = 4
formatter.minimumFractionDigits = 4
var str = formatter.stringFromNumber(num)
println("long: /(touchCoordinate.longitude)")
var num1 = (touchCoordinate.longitude as NSNumber).floatValue
var formatter1 = NSNumberFormatter()
formatter1.maximumFractionDigits = 4
formatter1.minimumFractionDigits = 4
var str1 = formatter1.stringFromNumber(num1)
self.adressLoLa.text = "/(num),/(num1)"
}
}
y quiero imprimir en annotation.title
la dirección completa (calle, ciudad, código postal, país).
SWIFT 4.0: EDITAR
MapKit
framework proporciona una forma de obtener detalles de direcciones a partir de las coordenadas.
Necesita usar geocodificación inversa del kit de mapas. CLGeocoder
clase CLGeocoder
se usa para obtener la ubicación de la dirección y la dirección desde la ubicación (coordenadas). El método reverseGeocodeLocation
devolverá los detalles de la dirección de las coordenadas.
Este método acepta CLLocation
como parámetro y devuelve CLPlacemark
, que contiene el diccionario de direcciones.
Entonces el método anterior se actualizará como:
@objc func didLongPressMap(sender: UILongPressGestureRecognizer) {
if sender.state == UIGestureRecognizerState.began {
let touchPoint = sender.location(in: mapView)
let touchCoordinate = mapView.convert(touchPoint, toCoordinateFrom: self.mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = touchCoordinate
annotation.title = "Your position"
mapView.addAnnotation(annotation) //drops the pin
print("lat: /(touchCoordinate.latitude)")
let num = touchCoordinate.latitude as NSNumber
let formatter = NumberFormatter()
formatter.maximumFractionDigits = 4
formatter.minimumFractionDigits = 4
_ = formatter.string(from: num)
print("long: /(touchCoordinate.longitude)")
let num1 = touchCoordinate.longitude as NSNumber
let formatter1 = NumberFormatter()
formatter1.maximumFractionDigits = 4
formatter1.minimumFractionDigits = 4
_ = formatter1.string(from: num1)
self.adressLoLa.text = "/(num),/(num1)"
// Add below code to get address for touch coordinates.
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: touchCoordinate.latitude, longitude: touchCoordinate.longitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Place details
var placeMark: CLPlacemark!
placeMark = placemarks?[0]
// Location name
if let locationName = placeMark.location {
print(locationName)
}
// Street address
if let street = placeMark.thoroughfare {
print(street)
}
// City
if let city = placeMark.subAdministrativeArea {
print(city)
}
// Zip code
if let zip = placeMark.isoCountryCode {
print(zip)
}
// Country
if let country = placeMark.country {
print(country)
}
})
}
}
Actualiza Swift 4
addressDictionary quedó en deprecated en iOS 11.0
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: 37.769193, longitude: -122.426512)
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Place details
var placeMark: CLPlacemark!
placeMark = placemarks?[0]
// Complete address as PostalAddress
print(placeMark.postalAddress as Any) // Import Contacts
// Location name
if let locationName = placeMark.name {
print(locationName)
}
// Street address
if let street = placeMark.thoroughfare {
print(street)
}
// Country
if let country = placeMark.country {
print(country)
}
})
Más datos pueden ser recuperados
nombre, vía, subThoroughfare, localidad, subLocality, administrativeArea, subAdministrativeArea, código postal, isoCountryCode, country, inlandWater, areaOfInterest
En el método didUpdateToLocation:
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:
(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation{
CLLocation *location = [locationManager location];
CLLocationCoordinate2D coordinate = [location coordinate];
latitude = [NSString stringWithFormat:@"%.12f", coordinate.latitude];
longitude = [NSString stringWithFormat:@"%.12f", coordinate.longitude];
CLLocation *location1 = [[CLLocation alloc]
initWithLatitude:latitude.floatValue
longitude:longitude.floatValue];
self.myGeocoder = [[CLGeocoder alloc] init];
[self.myGeocoder
reverseGeocodeLocation:location1
completionHandler:^(NSArray *placemarks, NSError *error) {
if (error == nil &&
[placemarks count] > 0){
placemark = [placemarks lastObject];
NSString* vendorLocation=[NSString stringWithFormat:@"%@ %@",
placemark.locality,
placemark.subLocality];
NSLog(@"%@",vendorLocation);
}
}];
}
Gracias a @Kampai por su respuesta, la revisé un poco para que funcione con Swift 1.2
:
var geocoder = CLGeocoder()
var location = CLLocation(latitude: IC.coordinate!.latitude, longitude: IC.coordinate!.longitude)
geocoder.reverseGeocodeLocation(location) {
(placemarks, error) -> Void in
if let placemarks = placemarks as? [CLPlacemark] where placemarks.count > 0 {
var placemark = placemarks[0]
println(placemark.addressDictionary)
}
Resultado:
[SubLocality: Sydney, calle: 141 Harrington Street, estado: NSW, SubThoroughfare: 141, CountryCode: AU, ZIP: 2000, calle: Harrington Street, nombre: 141 Harrington Street, país: Australia, líneas de dirección formateadas: ("141 Harrington Street" , "The Rocks NSW 2000", Australia), Ciudad: The Rocks]
Gracias a @Kampi por esto. Esta es una versión actualizada de Swift 2.0 (Xcode 7):
func setUsersClosestCity()
{
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: _point1.coordinate.latitude, longitude: _point1.coordinate.longitude)
geoCoder.reverseGeocodeLocation(location)
{
(placemarks, error) -> Void in
let placeArray = placemarks as [CLPlacemark]!
// Place details
var placeMark: CLPlacemark!
placeMark = placeArray?[0]
// Address dictionary
print(placeMark.addressDictionary)
// Location name
if let locationName = placeMark.addressDictionary?["Name"] as? NSString
{
print(locationName)
}
// Street address
if let street = placeMark.addressDictionary?["Thoroughfare"] as? NSString
{
print(street)
}
// City
if let city = placeMark.addressDictionary?["City"] as? NSString
{
print(city)
}
// Zip code
if let zip = placeMark.addressDictionary?["ZIP"] as? NSString
{
print(zip)
}
// Country
if let country = placeMark.addressDictionary?["Country"] as? NSString
{
print(country)
}
}
}
Gracias a la respuesta de @ Kampai , aquí hay una forma compatible y segura de Swift 3 (¡sin forzar !
):
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: touchCoordinate.latitude, longitude: touchCoordinate.longitude)
geoCoder.reverseGeocodeLocation(location, completionHandler: { placemarks, error in
guard let addressDict = placemarks?[0].addressDictionary else {
return
}
// Print each key-value pair in a new row
addressDict.forEach { print($0) }
// Print fully formatted address
if let formattedAddress = addressDict["FormattedAddressLines"] as? [String] {
print(formattedAddress.joined(separator: ", "))
}
// Access each element manually
if let locationName = addressDict["Name"] as? String {
print(locationName)
}
if let street = addressDict["Thoroughfare"] as? String {
print(street)
}
if let city = addressDict["City"] as? String {
print(city)
}
if let zip = addressDict["ZIP"] as? String {
print(zip)
}
if let country = addressDict["Country"] as? String {
print(country)
}
})
No se olvide de NSLocationWhenInUseUsageDescription
y NSLocationAlwaysUsageDescription
claves de NSLocationAlwaysUsageDescription
en Swift 3
Para Swift 3: y Swift 4
Primero, debe establecer la asignación para recibir el GPS del usuario en info.plist
.
Set: NSLocationWhenInUseUsageDescription
con una cadena aleatoria. Y / o: NSLocationAlwaysUsageDescription
con una cadena aleatoria.
Luego configuré una clase para obtener los datos deseados, como zip, ciudad, país ...:
import Foundation
import MapKit
typealias JSONDictionary = [String:Any]
class LocationServices {
let shared = LocationServices()
let locManager = CLLocationManager()
var currentLocation: CLLocation!
let authStatus = CLLocationManager.authorizationStatus()
let inUse = CLAuthorizationStatus.authorizedWhenInUse
let always = CLAuthorizationStatus.authorizedAlways
func getAdress(completion: @escaping (_ address: JSONDictionary?, _ error: Error?) -> ()) {
self.locManager.requestWhenInUseAuthorization()
if self.authStatus == inUse || self.authStatus == always {
self.currentLocation = locManager.location
let geoCoder = CLGeocoder()
geoCoder.reverseGeocodeLocation(self.currentLocation) { placemarks, error in
if let e = error {
completion(nil, e)
} else {
let placeArray = placemarks as? [CLPlacemark]
var placeMark: CLPlacemark!
placeMark = placeArray?[0]
guard let address = placeMark.addressDictionary as? JSONDictionary else {
return
}
completion(address, nil)
}
}
}
}
}
Llamado por:
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
LocationServices.shared.getAdress { address, error in
if let a = address, let city = a["City"] as? String {
//
}
}
}
}
Hecho
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))")
})
}
use este código, esto resolverá el problema.