Преобразовать координаты в название города?

Как получить адрес из координат с помощью MapKit?

У меня есть этот код, когда долгое нажатие на карту, он получает координаты:

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)"
                }
}

и я хочу напечатать в annotation.title полный адрес (улица, город, почтовый индекс, страна).

9 ответов

Решение

SWIFT 4.0: РЕДАКТИРОВАТЬ


MapKit Фреймворк предоставляет способ получить детали адреса из координат.

Вам необходимо использовать обратное геокодирование набора карт. CLGeocoder класс используется, чтобы получить местоположение от адреса и адрес от местоположения (координаты). Метод reverseGeocodeLocation вернет детали адреса из координат.

Этот метод принимает CLLocation в качестве параметра и возвращает CLPlacemark, который содержит адресный словарь.

Теперь вышеприведенный метод будет обновлен как:

   @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
                guard let placeMark = placemarks.first else { return }

                // 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)
                }
            })
        }
    }

Для Swift 3: и Swift 4

Сначала вам нужно установить допуск для получения GPS пользователя в info.plist,

введите описание изображения здесь

Задавать: NSLocationWhenInUseUsageDescription со случайной строкой. И / или: NSLocationAlwaysUsageDescription со случайной строкой.

Затем я настроил класс для получения желаемых данных, таких как почтовый индекс, город, страна...:

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)

                }

            }

        }

    }

}

Вызывается:

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 {
               //
            }

        }

    }

}

Готово

Обновить:

import Foundation
import CoreLocation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true

let location = CLLocation(latitude: 37.3321, longitude: -122.0318)
CLGeocoder().reverseGeocodeLocation(location) { placemarks, error in

    guard let placemark = placemarks?.first else {
        let errorString = error?.localizedDescription ?? "Unexpected Error"
        print("Unable to reverse geocode the given location. Error: \(errorString)")
        return
    }

    let reversedGeoLocation = ReversedGeoLocation(with: placemark)
    print(reversedGeoLocation.formattedAddress)
    // Apple Inc.,
    // 1 Infinite Loop,
    // Cupertino, CA 95014
    // United States
}

struct ReversedGeoLocation {
    let name: String            // eg. Apple Inc.
    let streetName: String      // eg. Infinite Loop
    let streetNumber: String    // eg. 1
    let city: String            // eg. Cupertino
    let state: String           // eg. CA
    let zipCode: String         // eg. 95014
    let country: String         // eg. United States
    let isoCountryCode: String  // eg. US

    var formattedAddress: String {
        return """
        \(name),
        \(streetNumber) \(streetName),
        \(city), \(state) \(zipCode)
        \(country)
        """
    }

    // Handle optionals as needed
    init(with placemark: CLPlacemark) {
        self.name           = placemark.name ?? ""
        self.streetName     = placemark.thoroughfare ?? ""
        self.streetNumber   = placemark.subThoroughfare ?? ""
        self.city           = placemark.locality ?? ""
        self.state          = placemark.administrativeArea ?? ""
        self.zipCode        = placemark.postalCode ?? ""
        self.country        = placemark.country ?? ""
        self.isoCountryCode = placemark.isoCountryCode ?? ""
    }
}

Старый / Устаревший ответ:

Благодаря ответу @Kampai, вот Swift 3- совместимый и безопасный способ (без форсирования !):

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

Не забывай NSLocationWhenInUseUsageDescription а также NSLocationAlwaysUsageDescription ключи в Свифт 3

Спасибо @Kampi за это. Это обновленная версия 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)
        }
    }
}

Спасибо @Kampai за его ответ, я немного пересмотрел, чтобы он работал с 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)
        }

Результат:

[Местонахождение: Сидней, улица: 141 Харрингтон-стрит, штат: Новый Южный Уэльс, субрайон: 141, CountryCode: AU, ZIP: 2000, магистраль: Харрингтон-стрит, Название: 141 Harrington Street, страна: Австралия, FormattedAddressLines: ( "141 Harrington Street"), "The Rocks NSW 2000", Австралия), Город: Скалы]

Swift 4.2. Сделайте его максимально простым, посмотрите документ Apple и измените его так, как вам нужно:

func retreiveCityName(lattitude: Double, longitude: Double, completionHandler: @escaping (String?) -> Void)
{
    let geocoder = CLGeocoder()
    geocoder.reverseGeocodeLocation(CLLocation(latitude: latitude, longitude: longitude), completionHandler:
    {
        placeMarks, error in

        completionHandler(placeMarks?.first?.locality)
     })
}

Обновление Swift 4

addressDictionary устарел в 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)
}
})

Больше данных можно получить

название, проезд, подрайон, населенный пункт, местность, административный район, административный район, почтовый индекс, isoCountryCode, страна, внутренний водный район, areaOfInterest

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



})
}

используйте этот код, это решит проблему.

В методе 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);
        }
    }];
}
Другие вопросы по тегам