CLPlacemark à la chaîne dans iOS 9

je veux formater CLPlacemark à la chaîne.

la façon bien connue est d'utiliser ABCreateStringWithAddressDictionary mais il a été déprécié dans iOS 9. Avertissement me dit d'utiliser CNPostalAddressFormatter à la place.

Cependant, CNPostalAddressFormatter ne peut format CNPostalAddress. Il n'y a aucun moyen de convertir correctement CLPlacemarkCNPostalAddress; seulement ces 3 propriétés sont partagées par CLPlacemark et CNPostalAddress:country,ISOcountryCode et postalCode.

alors comment dois-je formater CLPlacemark string maintenant?

22
demandé sur shim 2015-10-28 00:49:28

4 réponses

Prendre le repère addressDictionary et utiliser ses "FormattedAddressLines" touche pour extraire la chaîne d'adresse. Notez que ceci est un array des lignes de la chaîne.

(vous avez raison, cependant, que les développeurs Apple chargés de convertir au cadre de Contacts semblent avoir complètement oublié l'échange entre carnet d'adresses et CLPlacemark. Il s'agit d'un bogue grave dans le cadre des Contacts - un parmi tant d'autres.)

25
répondu matt 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
répondu guido 2017-04-27 18:32:01

Swift 4.1 (et 3 & 4, d'économiser 1 ligne)

j'ai lu la question pour demander " Comment puis-je mettre en œuvre ceci?':

extension String {
    init?(placemark: CLPlacemark?) {
        // Yadda, yadda, yadda
    }
}

Deux Méthodes

je suis d'abord allé pour le portage de la méthode AddressDictionary, comme l'ont fait d'autres affiches. Mais cela signifie perdre la puissance et la flexibilité de la CNPostalAddress la classe et le formateur. D'où la méthode 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))
    }
}

Attendez, ce est que CLPlacemarkCNPostalAddress initialiseur??

extension CNMutablePostalAddress {
    convenience init(placemark: CLPlacemark) {
        self.init()
        street = [placemark.subThoroughfare, placemark.thoroughfare]
            .compactMap {  }           // 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 ?? ""
        }
    }
}

Utilisation

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
*/

Quiconque lit jusqu'à ici obtient un T-shirt gratuit. (pas vraiment)

*ce code fonctionne dans Swift 3 & 4, sauf que flatMap pour supprimer les valeurs nulles a été déprécié / renommé à compactMap dans Swift 4.1 (Doc ici, ou SE-187 pour la justification).

6
répondu AmitaiB 2018-04-16 23:30:57

Méthode Swift 3.0 Helper

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
répondu Sourabh Sharma 2016-10-28 11:40:35