MapKit MapStyle

Does anybody know if I'm missing something here?

I'm using .mapStyle(.elevation(.realistic)), which enables the 3D map view, but it causes significant lag when driving in real life, especially at speeds above 50 mph.

Everything works perfectly in the Simulator with no issues, but real world performance is much worse. The phone starts heating up almost immediately when driving in this mode through urban areas with 3D map data.

Interestingly, the phone does not heat up on motorways, and performance is excellent there. (I guess because there's not so much 3D data to show on motorways)

This mode looks fantastic and is one of the most requested features from my users, so I'm trying to figure out how to make it work properly.

I've tested both SwiftUI and UIKit implementations and get the same result in both.

Also I'm using an iPhone 17 Pro Max and an iPad 11, same result on both, including CarPlay

import MapKit
import CoreLocation


struct ContentView: View {
    @State private var locationManager = LocationManagerDelegate()
    @State private var cameraPosition: MapCameraPosition = .userLocation(followsHeading: false, fallback: .automatic)
    @State private var isTracking: Bool = false
    
    var body: some View {
        Map(position: $cameraPosition) {
            UserAnnotation()
        }
        .mapStyle(.imagery(elevation: .realistic))
        .onChange(of: locationManager.location) { _, location in
            guard isTracking, let location else { return }
                        
            withAnimation(.linear(duration: 0.5)) {
                cameraPosition = .camera(MapCamera(
                    centerCoordinate: location.coordinate,
                    distance: 1000,
                    heading: location.course,
                    pitch: 60
                ))
            }
        }
        .safeAreaInset(edge: .bottom) {
            // Added to the safeAreaInset to keep the Apple Logo visible
            Button("Track") {
                isTracking.toggle()
                locationManager.requestPermission()
                locationManager.startNavigating()
            }
            .buttonStyle(.glassProminent)
            .buttonSizing(.flexible)
            .controlSize(.extraLarge)
            .padding(.horizontal)
        }
    }
}


@MainActor
@Observable
final class LocationManagerDelegate: NSObject, CLLocationManagerDelegate {
    var location: CLLocation?
    var authorizationStatus: CLAuthorizationStatus = .notDetermined
    
    let manager = CLLocationManager()
    private var liveUpdateTask: Task<Void, Never>?
    
    override init() {
        super.init()
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
        manager.allowsBackgroundLocationUpdates = true
        authorizationStatus = manager.authorizationStatus
    }
    
    func requestPermission() { manager.requestWhenInUseAuthorization() }
    
    func startNavigating() {
        liveUpdateTask = Task {
            do {
                for try await update in CLLocationUpdate.liveUpdates(.automotiveNavigation) {
                    guard let newLocation = update.location else { continue }
                    self.location = newLocation
                }
            } catch {
                print("Live updates error: \(error)")
            }
        }
    }
    
    func stopNavigating() {
        liveUpdateTask?.cancel()
        liveUpdateTask = nil
        manager.requestLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        location = locations.last
    }
    
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        authorizationStatus = manager.authorizationStatus
    }
}

#Preview {
    ContentView()
}

Thanks for the post.

For driving and navigation that is not the best style as will have issues with changing the zoom levels like this post here: https://developer.apple.com/forums/thread/823043

The .mapStyle(.elevation(.realistic)) modifier tells MapKit to render high-fidelity 3D terrain. The 3D geometry is sparse. The engine mostly renders flat terrain and trees, which are highly optimized. The map engine is forced to constantly stream, decode, and render thousands of complex 3D building polygons every second at that speed instead of using it as an overview. Ensure you are not manually forcing camera updates on every single CLLocation update. If you are binding the camera position manually, it can fight with MapKit's internal rendering loop and exacerbate performance issues.

For navigation I always suggest to switch to .mapStyle(.standard(elevation: .flat))

Hope this helps.

Albert  WWDR

MapKit MapStyle
 
 
Q