I'm working on an app that heavily uses addresses in different countries. We have a bunch of ways we input them from getting addresses imported, to dropping pins on map, to reverse geocode our current location.
My current project is to correctly format international address:
In the USA:
18 Street Name
In Norway:
Street Name 18
I've figured out a bunch of ways to instantiate CNMutablePostalAddress
with CLPlacemark
to get some pretty good results, the problem I'm having is this.
I want just the street name and number returned as a one line string:
So:
street1: placemarker.thoroughfare, (street name)
street2: placemarker.subThoroughfare (street number),
but CNPostalAddress only has one street
property, so to use it you need to do something like this:
cNPostalAddress.street = placemarker.subThoroughfare + " " + placemarker.thoroughfare
This will not work for countries like Norway where they are revered.
You can hack it and use the take the first line from the formatted address:
CNPostalAddressFormatter.string(from: placemarker.mailingAddress , style: .mailingAddress)
but that's super hacky and I'm sure it will break with countries that order their mailing address differently like japan.
At the moment I can't even find any resources that tell me which countries reverse subThoroughfare
and thoroughfare
, because if I had a list like that I could just reverse it manually.
Here is some sample code of what I've managed so far:
static func mulitLineAddress(from placemarker: CLPlacemark, detail: AddressDetail) -> String {
let address = MailingAddress(
street1: placemarker.thoroughfare,
street2: placemarker.subThoroughfare,
city: placemarker.locality,
state: placemarker.administrativeArea,
postalCode: placemarker.postalCode,
countryCode: placemarker.country)
return self.mulitLineAddress(from: address, detail: detail)
}
static func mulitLineAddress(from mailingAddress: MailingAddress, detail: AddressDetail) -> String {
let address = CNMutablePostalAddress()
let street1 = mailingAddress.street1 ?? ""
let street2 = mailingAddress.street2 ?? ""
let streetSpacing = street1.isEmpty && street2.isEmpty ? "" : " "
let streetFull = street1 + streetSpacing + street2
switch detail {
case .street1:
address.street = street1
case .street2:
address.street = street2
case .streetFull:
address.street = streetFull
case .full:
address.country = mailingAddress.countryCode ?? ""
fallthrough
case .withoutCountry:
address.street = streetFull
address.city = mailingAddress.city ?? ""
address.state = mailingAddress.state ?? ""
address.postalCode = mailingAddress.postalCode ?? ""
}
return CNPostalAddressFormatter.string(from: address, style: .mailingAddress)
}
Any ideas? Even resources like list of countries that reverse street1
and street2
would be useful.
CNPostalAddressFormatter
has an interesting API to get anNSAttributedString
where each address component is identified in it. You could use this to pull out just the information you want, like the street which includes the properly localized sub-thoroughfare and thoroughfare no matter where it may exist in the postal address.I've also filed feedback with Apple to add a more powerful and flexible API: FB8648023 Template API desired to format addresses with specified components similar to
DateFormatter.setLocalizedDateFormatFromTemplate