Home > Mobile >  @AppStorage property wrapper prevents from dismissing views
@AppStorage property wrapper prevents from dismissing views

Time:03-12

I have an app with four (4) views, on the first view I'm showing a list of cars pulled from CoreData, the second view is presented when a car is tapped and it shows the services for each car. The third view is presented when tapping on a service, and it shows the details of the selected service. The fourth view is presented when tapping a button and it shows records for the specified service.

The issue I'm having is that for some reason if I use an @AppStorage property wrapper within the ServicesView I cannot dismiss the fourth view (RecordsView). I don't think the issue is with CoreData but let me know if you need to see the code for Core Data.

Any idea why adding an @AppStorage property wrapper in the ServicesView would affect other views?

enter image description here

CarsView

    struct CarsView: View {
        @ObservedObject var carViewModel:CarViewModel
        @State private var carInfoIsPresented = false
        
        var body: some View {
            
            NavigationView{
                VStack{
                    List {
                        ForEach(carViewModel.cars) { car in
                            HStack{
                                VStack(alignment:.leading){
                                    Text(car.model ?? "")
                                        .font(.title2)
                                    Text(car.make ?? "")
                                        .foregroundColor(Color(UIColor.systemGray))
                                }
                                NavigationLink(destination: ServicesView(carViewModel: carViewModel, selectedCar: car)){
                                    Spacer()
                                    Text("Services")
                                        .frame(width: 55)
                                        .font(.caption)
                                        .foregroundColor(Color.systemGray)
                                }
                            }
                        }
                    }
                    .listStyle(GroupedListStyle())
                    .navigationBarTitle("Cars")
                    .accentColor(.white)
                    .padding(.top, 20)
                }  
            }
        }
    }

ServicesView

    struct ServicesView: View {
        @ObservedObject var carViewModel: CarViewModel
        var selectedCar: Car
        
        // ISSUE: No issues dismissing the RecordsView if I comment this out
        @AppStorage("sortByNameKey") private var sortByName = true

        @State private var selectedService: CarService?

        var body: some View {
            VStack{
                List {
                    ForEach(carViewModel.carServices) { service in
                        HStack{
                            Text(service.name ?? "")
                                .font(.title3)
                            
                            NavigationLink(destination: ServiceInfoView(carViewModel: carViewModel, selectedCar: selectedCar, selectedService: service)){
                                Spacer()
                                Text("Details")
                                    .font(.caption)
                                    .foregroundColor(Color.systemGray)
                            }
                        }
                    }
                }
                .navigationBarTitle(Text("\(selectedCar.model ?? "Services") - Services"))
                .listStyle(GroupedListStyle())
            }
            .onAppear{
                carViewModel.getServices(forCar: selectedCar)
            }
        }
    }

ServiceInfoView

    struct ServiceInfoView: View {
        @ObservedObject var carViewModel: CarViewModel
        @State private var recordsViewIsPresented = false
        @State var selectedCar: Car
        @State var selectedService: CarService
        
        var body: some View {
            VStack{
                Text(selectedService.name ?? "")
                    .font(.largeTitle)
                    .padding(.bottom)
                
                VStack{
                    Button(action: openRecordsView) {
                        Text("Service History")
                    }
                    .padding(10)
                    .background(Color.blue)
                    .foregroundColor(Color.white)
                    .cornerRadius(15)
                }
            }
            .sheet(isPresented: $recordsViewIsPresented){
                RecordsView(carViewModel: carViewModel, selectedService: selectedService)
            }
        }
        
        func openRecordsView(){
            recordsViewIsPresented.toggle()
        }
    }

RecordsView

    struct RecordsView: View {
        @ObservedObject var carViewModel: CarViewModel
        @State var selectedService: CarService
        @Environment(\.presentationMode) var presentationMode

        var body: some View {
            NavigationView {
                VStack{
                    List {
                        Section(header: Text("Records")) {
                            ForEach(carViewModel.serviceRecords) { record in
                                HStack{
                                    Text("Service Date:")
                                    Text("\(record.serviceDate ?? Date(), style: .date)")
                                        .foregroundColor(Color(UIColor.systemGray))
                                }
                            }
                        }
                    }
                    .background(Color.purple)
                    .listStyle(GroupedListStyle())
                }
                .navigationBarTitle("Records for \(selectedService.name ?? "")", displayMode: .inline)
                .navigationBarItems(leading: Button("Cancel", action: dismissView))
                .onAppear{
                    carViewModel.getRecords(forService: selectedService)
                }
            }
        }
        
        func dismissView(){
            presentationMode.wrappedValue.dismiss()
        }
    }

CodePudding user response:

NavigationView can only push one detail screen unless you set .isDetailLink(false) on the NavigationLink.

FYI we don't use view model objects in SwiftUI, you have to learn to use the View struct correctly along with @State, @Binding, @FetchRequest etc. that make the safe and efficient struct behave like an object. If you ignore this and use an object you'll experience the bugs that Swift with its value types was designed to prevent. For more info see this answer MVVM has no place in SwiftUI.

  • Related