With iOS 26, Apple deprecated CLGeocoder — the API developers have relied on since Core Location’s earliest days to turn a coordinate into a readable place: city, region, nearby point of interest. The replacement lives in MapKit: MKReverseGeocodingRequest.1

Let’s take one coordinate as an example, about 20 metres (60 feet) away from Cypress Mountain Resort’s main cabin, located in the city of West Vancouver, BC in Canada:

Coordinates <code>49.396840, -123.204116</code>, located 20 metres from Cypress Mountain Resort, in West Vancouver, BC, Canada.
Coordinates 49.396840, -123.204116, located 20 metres from Cypress Mountain Resort, in West Vancouver, BC, Canada.

Below is the code I ran both reverse-geocoding processes, side by side:

let location = CLLocation(latitude: 49.396840, longitude: -123.204116)

func geocoderLookup() async -> String {
    let coder = CLGeocoder()
    if let placemarks = try? await coder.reverseGeocodeLocation(location)
    {
        let output = placemarks.map({ mark in
            var output = ""
            output += (mark.areasOfInterest ?? []).joined(separator: " | ") + "\n"
            output += (mark.subLocality ?? "") + "\n"
            output += (mark.locality ?? "") + "\n"
            output += (mark.subAdministrativeArea ?? "") + "\n"
            output += (mark.administrativeArea ?? "") + "\n"
            output += (mark.country ?? "") + "\n"
            return output
        }).joined(separator: "\n\n")

        return output
    } else {
        return "Error"
    }
}

func mapkitLookup() async -> String {
    let request = MKReverseGeocodingRequest(location: location)
    let items = (try? await request?.mapItems) ?? []
    let output = items.map({ item in
        var output = ""
        output += "\(item.pointOfInterestCategory?.rawValue ?? "NA"): \(item.name ?? "No Name")" + "\n"
        output += (item.address?.fullAddress ?? "") + "\n"
        output += (item.address?.shortAddress ?? "") + "\n"
        output += (item.addressRepresentations?.cityName ?? "") + "\n"
        output += (item.addressRepresentations?.regionName ?? "") + "\n"
        output += (item.addressRepresentations?.cityWithContext(.full) ?? "") + "\n"
        output += (item.addressRepresentations?.cityWithContext(.short) ?? "") + "\n"
        output += (item.addressRepresentations?.cityWithContext(.automatic) ?? "") + "\n"
        output += (item.addressRepresentations?.fullAddress(includingRegion: true, singleLine: true) ?? "") + "\n"
        return output
    }).joined(separator: "\n\n")
    return output
}

Here are the results, side by side:

  CLGeocoder MapKit
Point of Interest a) Cypress Mountain
b) Cypress Provincial Park
Cypress Mountain
Neighbourhood Cypress Park 🫥 N/A
City ✅ West Vancouver ❌ Bowen Island
Area ✅ Metro Vancouver 🫥 N/A
Province ✅ BC ⚠️ (city), BC
Country ✅ Canada ✅ Canada
Postal Code ❌ V0N 1G2 ❌ V0N 1G2

First, about correctness

The most obvious points from the table above:

On all other fronts, CLGeocoder produces the correct results: The neighbourhood/sublocality of Cypress Mountain, the point of interest that is Cypress Provincial Park, the fact that this is the city of West Vancouver, located in Metro Vancouver, in BC, Canada.

MapKit named the neighbourhood, too, but it doesn’t know anything about it also being a provincial park. It placed the coordinate in the wrong city (the municipality of Bowen Island is an island across Howe Sound2, with no relationship to the mountain behind West Vancouver whatsoever), and it has no knowledge of the metropolitan area.

That’s not a formatting difference or a naming preference between two reasonable answers. It’s just wrong.

Then, beyond correctness

Beyond correctness, MapKit’s AddressRepresentations also don’t get me clean information that I can work with:

So the MapKit replacement is not only inaccurate, it contains less information and is harder to work with.

A replacement that (still) isn’t ready

I don’t doubt Apple will get MapKit’s reverse geocoding sorted out eventually — it clearly has all the right data, since it named the point of interest correctly. But “eventually” isn’t “now,” and CLGeocoder having a deprecation warning on it doesn’t change that its output is the one you can trust today. Until MapKit stops making mistakes like this, I’m not switching, warning or not.

  1. CLGeocoder’s documentation has a coy deprecation message of two words: “Use MapKit”. There’s no link to the docs of MapKit, and there is no example. The deprecation message is not even a complete sentence with a period. My cynical read is that whoever wrote this two-word deprecation message was too embarrassed to even write up a full sentence, or to furnish the deprecation with an example. 

  2. Just for the reference, here are Bowen Island and West Vancouver on the same map:

    The municipality of Bowen Island (the largest island) on the left, and the city of West Vancouver (the mainland) on the right.