0

I am getting a lot of "Publishing changes from within view updates is not allowed" when using this code and it is causing freezes / crashes.

The error is pretty much showing permanently whether I move around the map or not, so I'm a bit confused as to why this might be.

Any thoughts on what might be causing this please?

Thanks

import SwiftUI
import MapKit

struct MapView: View {
    
    @State private var region = MKCoordinateRegion()
    
    var stations:[StationPrix]
    @Binding var isFullScreen: Bool
    @Environment(\.scenePhase) var scenePhase
    @Binding var selected:Int
    
    @State var tracking:MapUserTrackingMode = .follow
    
    var body: some View {

        Map(coordinateRegion: $region, interactionModes: .all, showsUserLocation: true, userTrackingMode: .constant(tracking), annotationItems: stations) { station in
        
            MapAnnotation(coordinate: station.coordinate) {
                
                VStack(spacing: 0) {
                    Image(station.imageName)
                        .resizable()
                        .aspectRatio(contentMode: .fit)
                        .frame(width: station.imageName == "Station Service" ? 0 : 30 , height: station.imageName == "Station Service" ? 0 : 30)
                        .padding(.top, 5)
                    
                    VStack(spacing: 0) {
                        ForEach (station.prix,id: \.id) { prix in
                            
                            VStack(spacing: -3){
                                
                                HStack{
                                    Text("\(prix.nom)")
                                        .font(.system(size: 7, weight: .light, design: .default))
                                    Spacer()
                                }
                                .foregroundColor(Color.black)
                                
                                HStack{
                                    Text("\(prix.valeur?.toCurrencyFormat() ?? "nul")")
                                        .padding(.leading, 4)
                                        .font(.system(size: 12, weight: prix.isCheapest == true ? .regular: .light, design: .default))
                    
                                        .foregroundColor(prix.isCheapest == true ? Color.green : Color.black)
                                }
                            }
                        }
                        
                    }.padding(3)
                }
                .background(Color.white)
                .cornerRadius(10)
                .overlay(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(Color.black, lineWidth: 0.5).opacity(0.6)
                )
            }
        }
        
        .onAppear{
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.7) {
                
                tracking = .none
                
                region.span = MKCoordinateSpan(
                    latitudeDelta: 0.0925,
                    longitudeDelta: 0.0925
                )
            }
        }
    }
}


struct FullScreenMap: View {
    @Binding var isFullScreen:Bool
    @Binding var selected:Int
    var stations:[StationPrix]
    @Environment(\.dismiss) var dismiss
    
    var body: some View {
        ZStack {
            MapView(stations: stations, isFullScreen: $isFullScreen, selected: $selected )
                .edgesIgnoringSafeArea(.all)
                .accentColor(Color(.systemPink))
            VStack(alignment:.trailing) {
                Spacer()
                HStack {
                    
                    Button(action: {
                        
                        print ("Tapped")
                        
                        self.selected = 2
                        self.dismiss()
                        
                    }) {
                        HStack {
                            Image(systemName: "xmark")
                                .foregroundColor(.white)
                        }
                        .padding()
                        .background(Color.blue)
                        .mask(Circle())
                    }.frame(width: 60, height: 60)
                    
                }
            }
        }
    }
}
jat
  • 183
  • 3
  • 14
  • What is the purpose of `asyncAfter`? – vadian Sep 27 '22 at 07:09
  • There are too many missing parts to test your code (and any answers). Show a minimal example code: https://stackoverflow.com/help/minimal-reproducible-example. – workingdog support Ukraine Sep 27 '22 at 07:28
  • The code in the asncAfter has two purposes, It zooms the map into something reasonable where annotations can be seen and also stops the tracking so that you can move the map around. Surely not the best way to so this but it works. And isn't the cause of the error that I am seeing. – jat Sep 27 '22 at 08:21

1 Answers1

1

Well .constant(tracking) is a problem, .constant should only be used in Previews. Also your use of dispatch async in onAppear is a problem because what if the View disappears and the state is destroyed before the deadline? You can improve that by using .task which is automatically cancelled in this case and use task sleep to recreate dispatch async.

However, there is also a known bug in Map's userTrackingMode, which I reported under FB9990674, you can read more about it here:

SwiftUI Map causes "modifying state during view update"

malhal
  • 26,330
  • 7
  • 115
  • 133
  • OK, perfect thanks. I removed the constant and replaced it with $tracking which works thanks. I tried wrapping the dispatch async with a Task which still works but I am still getting getting the error. So I assume this is the bug that you reported. Thanks for your help – jat Oct 04 '22 at 06:02