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?

Author: shim, 2015-10-28

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

 25
Author: matt,
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
}
 13
Author: guido,
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 CLPlacemarkCNPostalAddress ¿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).

 6
Author: AmitaiB,
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
      }
 1
Author: Sourabh Sharma,
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