I need some help with the new reverse geocoding operation in iOS 26. Apple has some sample code under the topic MKReverseGeocodingRequest. I have been trying to fill in the missing pieces to display the actual location on the screen.
As I understand it, MKReverseGeocodingRequest
returns with an array of MKMapItem. But I can't get MKMapItem in a format for use with MKAddress
(fullAddress or shortAddress) or MKAddressRepresentation
(cityName, region, regionName, cityWithContext) to display within a view. I find it interesting that I can get the location to display with .name or .description, while neither are part of MKAddress or MKAddressRepresentation (Xcode AI suggested these).
Questions: With MKMapItem, how do I display the address with MKAddress or MKAddressRepresentation? Are there other address display options?
struct MyReverseGeocoderView: View {
let fountainCoordinates = [
CLLocation(latitude: 39.042617, longitude: -94.587526),
CLLocation(latitude: 40.774313, longitude: -73.970835),
CLLocation(latitude: -33.870986, longitude: 151.211786),
CLLocation(latitude: 41.875790, longitude: -87.618953),
]
@State var fountains: [MKMapItem]?
var body: some View {
VStack {
if let fountains {
ForEach(fountains, id: \.name) { item in
Text(item.description)
Text(item.name ?? "")
}
}
}
}
.task {
var fountainMapItems = [MKMapItem]()
for coordinate in fountainCoordinates {
if let request = MKReverseGeocodingRequest(location: coordinate) {
let mapitems = try? await request.mapItems
if let mapitem = mapitems?.first {
fountainMapItems.append(mapitem)
}
}
}
fountains = fountainMapItems
// The fountains `MKMapItems` array contains information describing
// details about the following places based on the provided coordinates:
//
// Mill Creek Park Fountain, Kansas City, Missouri
// Bethesda Terrace Fountain, Central Park, New York City
// Archibald Fountain, Sydney, Australia
// Buckingham Fountain, Chicago, Illinois
}
}
}
You could try this approach using MKMapItem
address
instance property, to display the fullAddress or shortAddress.
Similarly using addressRepresentations
.
Example code:
struct ContentView: View {
var body: some View {
MyReverseGeocoderView()
}
}
struct MyReverseGeocoderView: View {
let fountainCoordinates = [
CLLocation(latitude: 39.042617, longitude: -94.587526),
CLLocation(latitude: 40.774313, longitude: -73.970835),
CLLocation(latitude: -33.870986, longitude: 151.211786),
CLLocation(latitude: 41.875790, longitude: -87.618953),
]
@State private var fountains: [MKMapItem] = []
var body: some View {
VStack {
ForEach(fountains, id: \.name) { item in
// Text(item.description)
// Text(item.name ?? "")
Text(item.address?.fullAddress ?? "no data").foregroundStyle(.blue)
Text(item.address?.shortAddress ?? "no data").foregroundStyle(.red)
}
}
.task {
for coordinate in fountainCoordinates {
if let request = MKReverseGeocodingRequest(location: coordinate) {
do {
let mapitems = try await request.mapItems
if let mapitem = mapitems.first {
fountains.append(mapitem)
}
} catch {
print(error)
}
}
}
}
}
}
Note, for a more robust implementation use a unique identifier for the fountains
elements (required for the ForEach).
For example:
struct MyMapItem: Identifiable {
let id = UUID()
let mapItem: MKMapItem
}
struct MyReverseGeocoderView: View {
let fountainCoordinates = [
CLLocation(latitude: 39.042617, longitude: -94.587526),
CLLocation(latitude: 40.774313, longitude: -73.970835),
CLLocation(latitude: -33.870986, longitude: 151.211786),
CLLocation(latitude: 41.875790, longitude: -87.618953),
]
@State private var fountains: [MyMapItem] = []
var body: some View {
VStack {
ForEach(fountains) { item in
Text(item.mapItem.address?.fullAddress ?? "no data").foregroundStyle(.blue)
Text(item.mapItem.address?.shortAddress ?? "no data").foregroundStyle(.red)
}
}
.task {
for coordinate in fountainCoordinates {
if let request = MKReverseGeocodingRequest(location: coordinate) {
do {
let mapitems = try await request.mapItems
if let mapitem = mapitems.first {
fountains.append(MyMapItem(mapItem: mapitem))
}
} catch {
print(error)
}
}
}
}
}
}