Why is SwiftUI Map modifying the state of its calling struct, if no frame is assigned?

98 Views Asked by At

Setup:

My app uses a SwiftUI Map, essentially as

struct MapViewSWUI: View {
    @Binding private var show_map_modal: Bool
    @State private var region: MKCoordinateRegion
//…
    init(show_map_modal: Binding<Bool>) {
        self._show_map_modal = show_map_modal
        self.region = // Some computed region
//…
    var body: some View {       
//…
        Map(coordinateRegion: $region)
            .frame(width: 400, height: 300) // Some frame for testing
    }
}  

Using this code, I can show the map modally without problems.

Problem:

If I out comment the .frame view modifier, I get the runtime error

Modifying state during view update, this will cause undefined behavior.  

with the following stack frame:
enter image description here

Question:

Why is it in my case required to set a frame for the Map? This tutorial does it, but Apple's docs don't. How to do it right?

PS:

I have read this answer to a similar question and tried to catch the error with a runtime breakpoint, but it does not show anything interesting:
enter image description here

I found an answer to another questions related to the same error, but it doesn't apply here.

EDIT:

Workaround found, but not understood:

My map is presented modally from another view. This view has a state var that controls the presentation:

@State private var show_map_modal = false

The body of the view consists of a HStack with some views, and a fullScreenCover view modifier is applied to the HStack:

var body: some View {
    HStack {
    // …
    }
    .fullScreenCover(isPresented: $show_map_modal) {
        MapViewSWUI(show_map_modal: $show_map_modal, itemToBeDisplayed: viewItem)
            .ignoresSafeArea(edges: [.leading, .trailing])
        }
}  

If the map is presented in this way, no run time error is raised.

However, if I include (as it was done up to now) .top or .bottom in the edge set, the run time error Modifying state during view update is raised.
I would be glad for any hint to the reason.

1

There are 1 best solutions below

3
On

My guess is that the error is not related to the frame at all, but to the update of the region once the sheet is presented.

As you can see in my code, I update the region 3 seconds after presenting the seet. Then, the error shows up.

Could the be happening in your code?

struct ContentView: View {
    @State private var show_map_modal = false
    
    var body: some View {
        Button {
            show_map_modal.toggle()
        } label: {
            Text("Show me the map!")
        }
        .sheet(isPresented: $show_map_modal) {
            MapViewSWUI(show_map_modal: $show_map_modal)
        }
    }
}

struct MapViewSWUI: View {
    @Binding private var show_map_modal: Bool
    @State private var region: MKCoordinateRegion

    init(show_map_modal: Binding<Bool>) {
        self._show_map_modal = show_map_modal
        self.region = MKCoordinateRegion(
            center: CLLocationCoordinate2D(
                latitude: 51.507222,
                longitude: -0.1275),
            span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
        )
    }

    var body: some View {
        VStack(alignment: .trailing) {
            Button("Done") {
                show_map_modal.toggle()
            }
            .padding(10)
            
            Map(coordinateRegion: $region)
        }
//        .frame(width: 400, height: 300) // Some frame for testing
        .onAppear {
            DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                self.region = MKCoordinateRegion(
                    center: CLLocationCoordinate2D(
                        latitude: 31.507222,
                        longitude: -1.1275),
                    span: MKCoordinateSpan(latitudeDelta: 0.5, longitudeDelta: 0.5)
                )
            }
        }
    }
}

enter image description here