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()
}