Highlight
In iOS 26, MapKit ships PlaceDescriptor, a unified MKGeocodingRequest/MKReverseGeocodingRequest pair, a cycling transportType, and Look Around views in MapKit JS.
Core content
Many apps share the same map problem: you only have an address or a latitude/longitude pair, but you can’t get the rich place data that Apple Maps shows. The old options were either to draw a thin annotation yourself, or to call MKLocalSearch and sift through the results. Both feel awkward for CRM sync, passing values between App Intents, or referencing one specific place across processes.
This year MapKit adds PlaceDescriptor, shipped in the new GeoToolbox framework. It packs a commonName, address, coordinate, and device location into one structured reference, then hands it to MKMapItemRequest to resolve into a full MKMapItem. The resolved MapItem matches what you would get from a Place ID: the official name, icon, hours, and a Place Card all work out of the box.
Geocoding gets a single entry point too. MKGeocodingRequest (address to coordinate) and MKReverseGeocodingRequest (coordinate to address) replace CLGeocoder for MapKit work. The directions API adds transportType = .cycling, making cycling routes a first-class citizen for the first time. MapKit JS catches up with an interactive Look Around view and event callbacks, so the web can embed the 3D street view directly.
Detail
The minimal PlaceDescriptor needs one representation and a commonName:
// Creating and resolving a PlaceDescriptor with coordinate PlaceRepresentation
import GeoToolbox
import MapKit
let annaLiviaCoordinates = CLLocationCoordinate2D(
latitude: 53.347673,
longitude: -6.290198
)
let annaLiviaDescriptor = PlaceDescriptor(
representations: [.coordinate(annaLiviaCoordinates)],
commonName: "Anna Livia Fountain"
)
let request = MKMapItemRequest(placeDescriptor: annaLiviaDescriptor)
do {
annaLiviaMapItem = try await request.mapItem
} catch {
print("Error resolving placeDescriptor: \(error)")
}
Key points:
import GeoToolbox: PlaceDescriptor lives outside the main MapKit module, so import the new framework on its own.representations: [.coordinate(...)]: the representations array is ordered by precision, highest first. Here there is only a coordinate.commonName: must be a publicly known name (such as Sydney Opera House). Don’t pass private aliases like “Mom’s house” — they don’t help resolution.MKMapItemRequest(placeDescriptor:): asks the Apple Maps backend to resolve the descriptor into an MKMapItem.try await request.mapItem: throws on failure, so wrap it in do/catch.
If the source data is an address rather than a coordinate, swap the representation for .address (05:56):
// Creating and resolving a PlaceDescriptor with address PlaceRepresentation
import GeoToolbox
import MapKit
let address = "121-122 James's St, Dublin 8"
let descriptor = PlaceDescriptor(
representations: [.address(address)],
commonName: "Obelisk Fountain"
)
let request = MKMapItemRequest(placeDescriptor: descriptor)
do {
obeliskFountain = try await request.mapItem
} catch {
print("Error resolving placeDescriptor: \(error)")
}
Key points:
.address(address): pass the most complete address you have — street number, city, postal code — for a higher hit rate.- The order of the representations array matters. If the coordinate was reverse-derived from the address, list the address first.
- The resolution logic lives on the MapKit backend; the caller only supplies the description.
When passing a place across apps (for example, App Intents), use supportingRepresentations to attach IDs from several services (06:45):
// Creating a PlaceDescriptor with identifiers
import GeoToolbox
let annaLiviaCoordinates = CLLocationCoordinate2D(
latitude: 53.347673,
longitude: -6.290198
)
let identifiers = ["com.apple.MapKit" : "ICBB5FD7684CE949"]
let annaLiviaDescriptor = PlaceDescriptor(
representations: [.coordinate(annaLiviaCoordinates)],
commonName: "Anna Livia Fountain",
supportingRepresentations: [.serviceIdentifiers(identifiers)]
)
Key points:
serviceIdentifiersis a dictionary: the key is the map service’s bundle id (com.apple.MapKit), the value is that service’s place id.- If a MapKit identifier is present,
MKMapItemRequestuses it first, falling back to the coordinate or address representation only when that fails. - You can list IDs from several services side by side, so the receiver can pick the one its SDK understands. That is what makes PlaceDescriptor a good fit for App Intents parameters.
A cycling route is one extra line on the existing MKDirections.Request (16:06):
// Fetch a cycling route
let request = MKDirections.Request()
request.source = MKMapItem.forCurrentLocation()
request.destination = selectedItem
request.transportType = .cycling
let directions = MKDirections(request: request)
do {
let response = try await directions.calculate()
returnedRoutes = response.routes
} catch {
print("Error calculating directions: \(error)")
}
Key points:
transportType = .cycling: this year’s new case. Before, only walking, automobile, and transit were supported.MKMapItem.forCurrentLocation(): when the source is the current location, you don’t have to build a coordinate.directions.calculate()is still the async throwing API.- The returned
response.routescan be drawn straight on a SwiftUI Map withMapPolyline.
Reverse geocoding uses MKReverseGeocodingRequest instead of CLGeocoder (10:45):
// Reverse geocode with MapKit
import MapKit
let millCreekCoordinates = CLLocation(latitude: 39.042617, longitude: -94.587526)
if let request = MKReverseGeocodingRequest(location: millCreekCoordinates) {
do {
let mapItems = try await request.mapItems
millCreekMapItem = mapItems.first
} catch {
print("Error reverse geocoding location: \(error)")
}
}
Key points:
- The initializer returns an optional. If the
if letfails, the input coordinate is invalid. request.mapItemsreturns an MKMapItem array directly, skipping the CLPlacemark to MKMapItem conversion.- The first element is usually the best match, but check confidence against your business rules.
Takeaways
-
Feed your existing CRM or Excel address data into PlaceDescriptor. Many app backends only carry names and addresses, so they couldn’t render Apple Maps style annotations on the map. Why it pays off: once shipped, users see the official hours, phone number, and Place Card inside your app. How to start: replace
CLGeocoder.geocodeAddressStringwithPlaceDescriptor(representations: [.address(...)], commonName:)plusMKMapItemRequest. One change covers the whole import pipeline. -
Wire
transportType = .cyclinginto cycling apps. Until now you either reused walking routes or bolted on a third-party cycling API. Why it pays off: Apple Maps cycling data covers elevation, gradient, and bike-lane preferences, so the native experience is complete. How to start: add one line,request.transportType = .cycling, to your existingMKDirections.Requestcode. Verify route quality before exposing a mode switch to users. -
Use PlaceDescriptor as an App Intents parameter. Passing a CLLocation across apps loses the place name and the IDs. Why it pays off: Shortcuts and Siri can pass arguments like “the X store nearby” to your app reliably. How to start: switch the location field on existing IntentParameters to
PlaceDescriptor, and attach your service’s ID throughsupportingRepresentations. -
Embed Look Around views in MapKit JS. The web has long been stuck with 2D maps, sending users to third parties for street view. Why it pays off: travel and real-estate sites can show Apple’s 3D street view right on the detail page, which lifts time on page. How to start: fetch a Place with
mapkit.PlaceLookup, then buildmapkit.LookAround(container, place, options). UseLookAroundPreviewas a thumbnail placeholder and expand to the full view on click. -
Rewrite old
CLGeocodercalls asMKGeocodingRequestorMKReverseGeocodingRequest. The old API returns CLPlacemark, which still has to be converted to MKMapItem. Why it pays off: one fewer layer, one fewer place to fail. How to start: grep the codebase forCLGeocoder(), then swap address calls forMKGeocodingRequestand coordinate calls forMKReverseGeocodingRequest. Mind the optional initializer.
Related sessions
- Go further with MapKit — the full session on the same topic, covering PlaceDescriptor, cycling routes, Look Around, and unified map URLs.
- Get to know App Intents — the App Intents fundamentals; PlaceDescriptor is the recommended place-parameter type.
- What’s new in SwiftUI — the latest updates to SwiftUI’s Map view and MapContentBuilder.
- Develop for Shortcuts and Spotlight with App Intents — exposing PlaceDescriptor as an Intent parameter for Shortcuts and Spotlight.
Comments
GitHub Issues · utterances