CLPlacemark a cadena en iOS 9
Quiero formatear CLPlacemark
a cadena.
La forma más conocida es usar ABCreateStringWithAddressDictionary
pero fue obsoleta en iOS 9. La advertencia me dice que use CNPostalAddressFormatter
en su lugar.
Sin embargo, CNPostalAddressFormatter
solo puede formatear CNPostalAddress
. No hay manera de convertir correctamente CLPlacemark
a CNPostalAddress
; solo estas 3 propiedades son compartidas por CLPlacemark
y CNPostalAddress
: country
, ISOcountryCode
, y postalCode
.
Entonces, ¿cómo debería formatear CLPlacemark
a string ahora?
4 answers
Tome la marca de posición addressDictionary
y use su tecla "FormattedAddressLines"
para extraer la cadena de dirección. Tenga en cuenta que este es un array de las líneas de la cadena.
(Tienes razón, sin embargo, que los desarrolladores de Apple encargados de convertir al marco de contactos parecen haber olvidado por completo el intercambio entre la libreta de direcciones y CLPlacemark. Este es un error grave en el marco de contactos, uno de muchos.)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-27 23:46:02
Swift 3.0
if let lines = myCLPlacemark.addressDictionary?["FormattedAddressLines"] as? [String] {
let placeString = lines.joined(separator: ", ")
// Do your thing
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-27 18:32:01
Swift 4.1 (y 3 & 4, guardar 1 línea)
Leí la pregunta para preguntar '¿Cómo podría implementar esto?':
extension String {
init?(placemark: CLPlacemark?) {
// Yadda, yadda, yadda
}
}
Dos Métodos
Primero fui a portar el método AddressDictionary, al igual que otros carteles. Pero eso significa perder el poder y la flexibilidad de la clase y formateador CNPostalAddress
. Por lo tanto, el método 2.
extension String {
// original method (edited)
init?(depreciated placemark1: CLPlacemark?) {
// UPDATE: **addressDictionary depreciated in iOS 11**
guard
let myAddressDictionary = placemark1?.addressDictionary,
let myAddressLines = myAddressDictionary["FormattedAddressLines"] as? [String]
else { return nil }
self.init(myAddressLines.joined(separator: " "))
}
// my preferred method - let CNPostalAddressFormatter do the heavy lifting
init?(betterMethod placemark2: CLPlacemark?) {
// where the magic is:
guard let postalAddress = CNMutablePostalAddress(placemark: placemark2) else { return nil }
self.init(CNPostalAddressFormatter().string(from: postalAddress))
}
}
Espera, ¿qué es eso CLPlacemark
→ CNPostalAddress
¿inicializador??
extension CNMutablePostalAddress {
convenience init(placemark: CLPlacemark) {
self.init()
street = [placemark.subThoroughfare, placemark.thoroughfare]
.compactMap { $0 } // remove nils, so that...
.joined(separator: " ") // ...only if both != nil, add a space.
/*
// Equivalent street assignment, w/o flatMap + joined:
if let subThoroughfare = placemark.subThoroughfare,
let thoroughfare = placemark.thoroughfare {
street = "\(subThoroughfare) \(thoroughfare)"
} else {
street = (placemark.subThoroughfare ?? "") + (placemark.thoroughfare ?? "")
}
*/
city = placemark.locality ?? ""
state = placemark.administrativeArea ?? ""
postalCode = placemark.postalCode ?? ""
country = placemark.country ?? ""
isoCountryCode = placemark.isoCountryCode ?? ""
if #available(iOS 10.3, *) {
subLocality = placemark.subLocality ?? ""
subAdministrativeArea = placemark.subAdministrativeArea ?? ""
}
}
}
Uso
func quickAndDirtyDemo() {
let location = CLLocation(latitude: 38.8977, longitude: -77.0365)
CLGeocoder().reverseGeocodeLocation(location) { (placemarks, _) in
if let address = String(depreciated: placemarks?.first) {
print("\nAddress Dictionary method:\n\(address)") }
if let address = String(betterMethod: placemarks?.first) {
print("\nEnumerated init method:\n\(address)") }
}
}
/* Output:
Address Dictionary method:
The White House 1600 Pennsylvania Ave NW Washington, DC 20500 United States
Enumerated init method:
1600 Pennsylvania Ave NW
Washington DC 20500
United States
*/
Quien lea hasta aquí recibe una camiseta gratis. (ni realmente)
*Este código funciona en Swift 3 & 4, excepto que flatMap
para eliminar los valores nil se ha depreciado/renombrado a compactMap
en Swift 4.1 (Doc aquí, o ver SE-187 para la justificación).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-16 23:30:57
Método auxiliar Swift 3.0
class func addressFromPlacemark(_ placemark:CLPlacemark)->String{
var address = ""
if let name = placemark.addressDictionary?["Name"] as? String {
address = constructAddressString(address, newString: name)
}
if let city = placemark.addressDictionary?["City"] as? String {
address = constructAddressString(address, newString: city)
}
if let state = placemark.addressDictionary?["State"] as? String {
address = constructAddressString(address, newString: state)
}
if let country = placemark.country{
address = constructAddressString(address, newString: country)
}
return address
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-28 11:40:35