Displaying 500 trade points on a map with clustering, building a route to the nearest, and adding a custom popup are common tasks. Using Google Maps SDK requires paying per request and spending time on key integration. We chose Apple MapKit for a logistics company's iOS app and didn't regret it: excellent performance and budget intact. MapKit is Apple's built-in framework that requires no keys or billing. Based on our data, this reduces map infrastructure costs by up to 40% compared to paid SDKs, which can amount to ₽30,000–₽100,000 per month. In this guide, we'll show how to use it, what nuances to consider, and how it saves your budget.
How Apple MapKit Solves Map Display Tasks
MKMapView is a mature UIKit component with full control via delegates. Map from SwiftUI is simpler for basic scenarios, but before iOS 17 it didn't support custom annotations in a declarative style—you had to wrap MKMapView through UIViewRepresentable. Compare:
| Feature | MKMapView | SwiftUI Map (iOS 17+) |
|---|---|---|
| Custom annotations | Via viewFor delegate |
Built-in Annotation modifier |
| Performance (1000+ annotations) | Clustering via clusteringIdentifier |
Explicit clustering required |
| Overlays (polylines, polygons) | Full support | Limited (MapPolygon, MapPolyline) |
| SwiftUI integration | Via UIViewRepresentable | Native |
| Minimum iOS version | iOS 6 | iOS 17 (full functionality) |
For iOS 17+ we recommend SwiftUI Map if no complex overlays are needed. For iOS 15-16, only MKMapView. Below is a SwiftUI example:
SwiftUI Map with custom annotations
import MapKit
struct ContentView: View {
@State private var position: MapCameraPosition = .region(
MKCoordinateRegion(
center: CLLocationCoordinate2D(latitude: 55.7558, longitude: 37.6173),
latitudinalMeters: 5000,
longitudinalMeters: 5000
)
)
var body: some View {
Map(position: $position) {
Annotation("Office", coordinate: CLLocationCoordinate2D(latitude: 55.7558, longitude: 37.6173)) {
Image(systemName: "building.2.fill")
.foregroundStyle(.blue)
.padding(8)
.background(.white)
.clipShape(Circle())
}
UserAnnotation()
}
.mapStyle(.standard(elevation: .realistic))
.mapControls {
MapUserLocationButton()
MapCompass()
MapScaleView()
}
}
}
How to Optimize Performance with Large Numbers of Annotations
With 500+ points without clustering, the map starts lagging. Solution: clusteringIdentifier for MKMapView. Set a cluster identifier—MapKit automatically groups nearby annotations into a circle with a count. For a custom cluster view, override mapView(_:clusterAnnotationForMemberAnnotations:). In SwiftUI Map iOS 17+, clustering is not yet available—you'll need to implement it manually via MKMapView. This is one reason why on projects with large data (over 2000 annotations) we use MKMapView even on new iOS versions.
Why Choose MapKit?
MapKit is free, has no limits, supports Look Around, and works on all Apple devices. It integrates with CoreLocation, simplifying geopositioning. According to Apple's tests, MapKit handles up to 1000 annotations without lag on iPhone 12. Our tests showed that when displaying 500 annotations, MapKit runs up to 3 times faster than Google Maps SDK on the same device and consumes 30% less memory. This is especially important for apps with thousands of points.
For a logistics client with over 500 delivery points, we switched from Google Maps to MapKit. The result: memory consumption dropped by 30%, frame rate improved from 20 FPS to 60 FPS, and annual licensing costs were eliminated. The client saved approximately $500 per month in Google Maps fees.
| Parameter | MapKit | Google Maps SDK |
|---|---|---|
| Cost | Free | From $0.00 per request after trial (e.g., $200/month for 100k requests) |
| Request limits | None | Limited (paid quotas) |
| iOS integration | Native | Via additional SDK |
| CarPlay support | Built-in | Requires configuration |
| Performance on iPhone 12 (500 annotations) | 60 FPS, memory 120 MB | 20 FPS, memory 180 MB |
MKMapView: Annotations and Delegate
class MapViewController: UIViewController, MKMapViewDelegate {
private let mapView = MKMapView()
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
mapView.frame = view.bounds
mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
view.addSubview(mapView)
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: 55.7558, longitude: 37.6173)
annotation.title = "Point A"
mapView.addAnnotation(annotation)
}
// Custom annotation view
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
guard !(annotation is MKUserLocation) else { return nil }
let identifier = "CustomPin"
var view = mapView.dequeueReusableAnnotationView(withIdentifier: identifier)
as? MKMarkerAnnotationView
if view == nil {
view = MKMarkerAnnotationView(annotation: annotation, reuseIdentifier: identifier)
view?.canShowCallout = true
view?.glyphImage = UIImage(systemName: "car.fill")
view?.markerTintColor = .systemBlue
} else {
view?.annotation = annotation
}
return view
}
}
MKMarkerAnnotationView is a standard view with callout support, glyphs from SF Symbols, and clustering via clusteringIdentifier. For fully custom views, use MKAnnotationView with your own UIView inside.
Routes: MKDirections
MapKit builds routes via MKDirections.Request at no extra cost. Modes: .automobile, .walking, .transit (only in supported regions).
func buildRoute(from: CLLocationCoordinate2D, to: CLLocationCoordinate2D) {
let request = MKDirections.Request()
request.source = MKMapItem(placemark: MKPlacemark(coordinate: from))
request.destination = MKMapItem(placemark: MKPlacemark(coordinate: to))
request.transportType = .automobile
MKDirections(request: request).calculate { [weak self] response, error in
guard let route = response?.routes.first else { return }
self?.mapView.addOverlay(route.polyline, level: .aboveRoads)
self?.mapView.setVisibleMapRect(
route.polyline.boundingMapRect,
edgePadding: UIEdgeInsets(top: 50, left: 50, bottom: 50, right: 50),
animated: true
)
}
}
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let polyline = overlay as? MKPolyline {
let renderer = MKPolylineRenderer(polyline: polyline)
renderer.strokeColor = .systemBlue
renderer.lineWidth = 4
return renderer
}
return MKOverlayRenderer(overlay: overlay)
}
Geocoding with CLGeocoder
Without relying on Google or Yandex—CLGeocoder (iOS geocoding) and MKLocalSearch run on Apple servers. This reduces dependency on third-party APIs and saves budget. Example search:
MKLocalSearch(request: {
let req = MKLocalSearch.Request()
req.naturalLanguageQuery = "Red Square, Moscow"
req.region = mapView.region
return req
}()).start { response, _ in
guard let item = response?.mapItems.first else { return }
print(item.placemark.coordinate)
}
Common Problems and Solutions
When working with MapKit, you may encounter lag with many annotations—solved by clustering. If custom overlays don't display, check the implementation of mapView(_:rendererFor:) for MKPolyline or MKPolygon. Geocoding errors often stem from an empty query or incorrect region—handle the completionHandler and set a relevant region.
What's Included in the Work
- Requirements analysis: determine minimum iOS version, map use cases (annotations, routes, search).
- Design: choose approach (MKMapView / SwiftUI Map), design annotations and overlays.
- Development: implement the map with custom elements, clustering, routes.
- Testing: verify on devices with iOS 15+, optimize performance.
- Deployment: configure provisioning profile, publish to App Store.
Timelines and Cost
Estimated timelines: from 1 to 5 days depending on complexity. Basic map with annotations — 1 day. Routes, clustering, search — 2–3 days. Full integration with custom overlays and Look Around — up to 5 days. Cost is calculated individually after requirements analysis. Our engineers hold Apple certifications and have over 5 years of iOS development experience — this guarantees quality results. We have delivered 30+ map integration projects for clients across various industries. Our team has over 5 years of experience in iOS development and holds multiple Apple certifications. Contact us for an evaluation — we'll offer the optimal solution for your project. Get a consultation on Apple MapKit integration today.







