Swift-создание формата адреса из обратного геокодирования
Я пытаюсь создать отформатированный полный адрес с помощью CLGeocoder в Swift 8. Я говорил об этом так нить, чтобы получить код, приведенный ниже.
однако иногда приложение падает с ошибкой " nil " в строке:
//Address dictionary
print(placeMark.addressDictionary ?? "")
вопросы:
- как я могу объединить эти значения, полученные из геокодера, чтобы сформировать полный адрес? (Улица + город + etc)
- как мне справиться с нулевой ошибкой, которую я получаю, когда func не может найти адрес?
полный код:
func getAddress() -> String {
var address: String = ""
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: selectedLat, longitude: selectedLon)
//selectedLat and selectedLon are double values set by the app in a previous process
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Place details
var placeMark: CLPlacemark!
placeMark = placemarks?[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)
}
})
return address;
}
7 ответов
func getAddressFromLatLon(pdblLatitude: String, withLongitude pdblLongitude: String) {
var center : CLLocationCoordinate2D = CLLocationCoordinate2D()
let lat: Double = Double("\(pdblLatitude)")!
//21.228124
let lon: Double = Double("\(pdblLongitude)")!
//72.833770
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)
{
print("reverse geodcode fail: \(error!.localizedDescription)")
}
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! + ", "
}
if pm.postalCode != nil {
addressString = addressString + pm.postalCode! + " "
}
print(addressString)
}
})
}
Это мой код 4 swift 3
func getAdressName(coords: CLLocation) {
CLGeocoder().reverseGeocodeLocation(location) { (placemark, error) in
if error != nil {
print("Hay un error")
} else {
let place = placemark! as [CLPlacemark]
if place.count > 0 {
let place = placemark![0]
var adressString : String = ""
if place.thoroughfare != nil {
adressString = adressString + place.thoroughfare! + ", "
}
if place.subThoroughfare != nil {
adressString = adressString + place.subThoroughfare! + "\n"
}
if place.locality != nil {
adressString = adressString + place.locality! + " - "
}
if place.postalCode != nil {
adressString = adressString + place.postalCode! + "\n"
}
if place.subAdministrativeArea != nil {
adressString = adressString + place.subAdministrativeArea! + " - "
}
if place.country != nil {
adressString = adressString + place.country!
}
self.lblPlace.text = adressString
}
}
}
}
Вы можете:
let cityCoords = CLLocation(latitude: newLat, longitude: newLon)
cityData(coord: cityCoords)
для объединения вы можете просто заменить return address
это :
return "\(locationName), \(street), \(city), \(zip), \(country)"
- для устранения проблемы с пустым адресом вы можете использовать свойство класса для хранения добавленного значения или использовать закрытие, чтобы вернуть значение вызывающей функции
- для фиксации аварии вам нужно, чтобы избежать силы разворачивания optionals
используя закрытие, вы можете сделать это так:
// Using closure
func getAddress(handler: (String) -> Void)
{
var address: String = ""
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: selectedLat, longitude: selectedLon)
//selectedLat and selectedLon are double values set by the app in a previous process
geoCoder.reverseGeocodeLocation(location, completionHandler: { (placemarks, error) -> Void in
// Place details
var placeMark: CLPlacemark?
placeMark = placemarks?[0]
// Address dictionary
//print(placeMark.addressDictionary ?? "")
// Location name
if let locationName = placeMark?.addressDictionary?["Name"] as? String {
address += locationName + ", "
}
// Street address
if let street = placeMark?.addressDictionary?["Thoroughfare"] as? String {
address += street + ", "
}
// City
if let city = placeMark?.addressDictionary?["City"] as? String {
address += city + ", "
}
// Zip code
if let zip = placeMark?.addressDictionary?["ZIP"] as? String {
address += zip + ", "
}
// Country
if let country = placeMark?.addressDictionary?["Country"] as? String {
address += country
}
// Passing address back
handler(address)
})
}
вы можете вызвать метод, как:
getAddress { (address) in
print(address)
}
Keeping it simple - полный Swift 3 & 4 совместимый пример контроллера просмотра для получения форматированной адресной строки из местоположения пользователя (добавьте другие ключи, доступные в CLPlacemark Если вы хотите получить больше информации в строке):
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let manager = CLLocationManager()
let geocoder = CLGeocoder()
var locality = ""
var administrativeArea = ""
var country = ""
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
manager.stopUpdatingLocation()
geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error) in
if (error != nil) {
print("Error in reverseGeocode")
}
let placemark = placemarks! as [CLPlacemark]
if placemark.count > 0 {
let placemark = placemarks![0]
self.locality = placemark.locality!
self.administrativeArea = placemark.administrativeArea!
self.country = placemark.country!
}
})
}
func userLocationString() -> String {
let userLocationString = "\(locality), \(administrativeArea), \(country)"
return userLocationString
}
}
вызов print(userLocationString()) в этом примере будет печатать: suburb, state, country
не забудьте добавить Конфиденциальность-Расположение При Использовании Описание Использования в свой Информация.plist файл заранее, чтобы позволить пользователю предоставлять разрешения для вашего приложения, чтобы использовать службы определения местоположения.
адреса форматирования трудно, потому что каждая страна имеет свой собственный формат. Пусть Apple сделает это:
начиная с iOS 11, Вы можете получить адрес рамки контактов:
extension CLPlacemark {
@available(iOS 11.0, *)
open var postalAddress: CNPostalAddress? { get }
}
это расширение является частью Contacts
основы.
Это означает, что эта функция невидима для вас в XCode
завершение кода, пока вы не сделаете
import Contacts
С этим addintional импорт, вы можете сделать что-то вроде
CLGeocoder().reverseGeocodeLocation(location, preferredLocale: nil) { (clPlacemark: [CLPlacemark]?, error: Error?) in
guard let place = clPlacemark?.first else {
print("No placemark from Apple: \(String(describing: error))")
return
}
let postalAddressFormatter = CNPostalAddressFormatter()
postalAddressFormatter.style = .mailingAddress
var addressString: String?
if let postalAddress = place.postalAddress {
addressString = postalAddressFormatter.string(from: postalAddress)
}
}
и получить адрес, отформатированный в формате для страна в адресе.
форматер даже поддерживает форматирование как attributedString.
до iOS 11 вы можете конвертировать CLPlacemark
to CNPostalAddress
вы и по-прежнему можете использовать форматирование конкретной страны CNPostalAddressFormatter
.
CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: vehicleLocation.latitude, longitude: vehicleLocation.latitude), completionHandler: {(placemarks, error) -> Void in
guard error == nil else {completionHandler(nil); return}
guard let place = placemarks else {completionHandler(nil); return}
if place.count > 0 {
let pm = place[0]
var addArray:[String] = []
if let name = pm.name {
addArray.append(name)
}
if let thoroughfare = pm.thoroughfare {
addArray.append(thoroughfare)
}
if let subLocality = pm.subLocality {
addArray.append(subLocality)
}
if let locality = pm.locality {
addArray.append(locality)
}
if let subAdministrativeArea = pm.subAdministrativeArea {
addArray.append(subAdministrativeArea)
}
if let administrativeArea = pm.administrativeArea {
addArray.append(administrativeArea)
}
if let country = pm.country {
addArray.append(country)
}
if let postalCode = pm.postalCode {
addArray.append(postalCode)
}
let addressString = addArray.joined(separator: ",\n")
print(addressString)
completionHandler(addressString)
}
else { completionHandler(nil)}
})