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 CLPlacemark
CNPostalAddress
; 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?
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.)
Swift 3.0
if let lines = myCLPlacemark.addressDictionary?["FormattedAddressLines"] as? [String] {
let placeString = lines.joined(separator: ", ")
// Do your thing
}
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 CLPlacemark
→CNPostalAddress
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).
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
}