Search code examples
iosswiftswiftuimapkitmapkitannotation

SwiftUI MapKit - MapAnnotation - cause so many view updates errors - Can we use it in Production release?


I want to use MapKit along with MapAnnotation in SwiftUI. So I can have custom views as map pins and add tap gestures to them later.

But when I run the app, Xcode starts to show so many UI errors:

Publishing changes from within view updates is not allowed, this will cause undefined behavior.

The Code is as simple as we can find, even in apple documentation or the ones below from hacking with swift

    import SwiftUI
    import MapKit

    struct Location: Identifiable {
        let id = UUID()
        let name: String
        let coordinate: CLLocationCoordinate2D
    }

    struct MapView: View {

        @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.5, longitude: -0.12), span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2))
        
        let locations = [
            Location(name: "Buckingham Palace", coordinate: CLLocationCoordinate2D(latitude: 51.501, longitude: -0.141)),
            Location(name: "Tower of London", coordinate: CLLocationCoordinate2D(latitude: 51.508, longitude: -0.076))
        ]
        
        var body: some View {
            Map(coordinateRegion: $region, annotationItems: locations) { location in
                MapAnnotation(coordinate: location.coordinate) {
                    Circle()
                        .stroke(.red, lineWidth: 3)
                        .frame(width: 44, height: 44)
                }
            }
            .navigationTitle("Map")
            .edgesIgnoringSafeArea(.all)
        }
    }

Would you happen to have any suggestions or workaround?

Can we use MapKit with these huge errors in a Production Release?


UPDATE

Based on recent answer, As a workaround, using a specific Binding<MKCoordinateRegion>() for the coordinateRegion, removes the warning/error.

But if you want to move the map based on the selected pin, those errors/warnings will appear again.

struct MapView: View {

    @State private var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.5, longitude: -0.12), span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2))
    
    let locations = [
        Location(name: "Buckingham Palace", coordinate: CLLocationCoordinate2D(latitude: 51.501, longitude: -0.141)),
        Location(name: "Tower of London", coordinate: CLLocationCoordinate2D(latitude: 51.508, longitude: -0.076))
    ]
    
    @State var selectedLocation: Location?

    var body: some View {
        ZStack {
            Map(coordinateRegion: Binding<MKCoordinateRegion>(
                get: { region },
                set: { _ in }
            ), annotationItems: locations) { location in
                MapAnnotation(coordinate: location.coordinate) {
                    Circle()
                        .stroke(.red, lineWidth: 3)
                        .frame(width: 44, height: 44)
                        .onTapGesture {
                            selectedLocation = location
                        }
                }
            }
        }
        .onChange(of: selectedLocation) { newValue in
            if let location = newValue {
                withAnimation {
                    region = MKCoordinateRegion(center: location.coordinate, span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2))
                }
            }
        }
        .edgesIgnoringSafeArea(.all)
    }
}

Solution

  • As a workaround, using a specific Binding<MKCoordinateRegion>() for the coordinateRegion, removes the warning/error for me.

    struct MapView: View {
        @State var region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 51.5, longitude: -0.12), span: MKCoordinateSpan(latitudeDelta: 0.2, longitudeDelta: 0.2))
        
        let locations = [
            Location(name: "Buckingham Palace", coordinate: CLLocationCoordinate2D(latitude: 51.501, longitude: -0.141)),
            Location(name: "Tower of London", coordinate: CLLocationCoordinate2D(latitude: 51.508, longitude: -0.076))
        ]
    
        var body: some View {
            Map(coordinateRegion: Binding<MKCoordinateRegion>(
                get: { region },
                set: { _ in }
            ), annotationItems: locations) { location in
                MapAnnotation(coordinate: location.coordinate) {
                    Circle().stroke(.red, lineWidth: 3).frame(width: 44, height: 44)
                }
            }
             .navigationTitle("Map")
             .edgesIgnoringSafeArea(.all)
        }
    }