Search code examples
iosswiftswiftuialertswiftui-alert

SwiftUI alert is not displaying when navigating to screen second time


I have one application in which i am making api call, in this application i want to display error if API does not return the response. When i navigate first time to the screen, it displays alert message, but when i go back to previous screen and again navigate back to same screen. alert is not displayed.

struct DashboardView: View {

@ObservedObject var viewModel = DashboardViewModel()
@State private var showingAlert = true

init() {
    UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.black]
    self.showingAlert = true
}

var body: some View {
        ZStack {
            Color.white
            if case .LOADING = viewModel.currentState {

                loaderView()
                .onAppear(perform: viewModel.getDashboardData)
            } else if case .SUCCESS(let dashboard) = viewModel.currentState {
                ScrollView(.vertical, showsIndicators: false) {
                    VStack(alignment: .leading, spacing: 10) {
                        HStack {
                            Text("Date:")
                                .foregroundColor(Color.black)
                            Text(dashboard.date)
                                .foregroundColor(Color.black)
                        }
                        VStack(alignment: .leading) {
                            Text("HDURL:")
                                .foregroundColor(Color.black)
                            Text(dashboard.hdurl)
                                .foregroundColor(Color.black)
                        }

                        HStack {
                            Text("Media Type:")
                                .foregroundColor(Color.black)
                            Text(dashboard.mediaType)
                                .foregroundColor(Color.black)
                        }
                        HStack {
                            Text("Service Version:")
                                .foregroundColor(Color.black)
                            Text(dashboard.serviceVersion)
                                .foregroundColor(Color.black)
                        }
                        VStack(alignment: .leading) {
                            Text("Title:")
                                .foregroundColor(Color.black)
                            Text(dashboard.title)
                                .foregroundColor(Color.black)
                        }
                        VStack(alignment: .leading) {
                            Text("url:")
                                .foregroundColor(Color.black)
                            Text(dashboard.url)
                                .foregroundColor(Color.black)
                        }
                        VStack(alignment: .leading) {
                            Text("Explanation:")
                                .foregroundColor(Color.black)
                            Text(dashboard.explanation)
                                .foregroundColor(Color.black)
                        }
                    }
                    .padding(.horizontal, 10)
                    .padding(.top, UIApplication.shared.keyWindow!.safeAreaInsets.top )

                }
                .padding(.top, UIApplication.shared.keyWindow!.safeAreaInsets.top )
            } else if case .FAILURE(let error) = viewModel.currentState {
                VStack {
                    Text("No Data")
                        .foregroundColor(Color.black)
                }

          
            }

        }
         .navigationBarTitle("Dashboard", displayMode: .inline)
         .alert(item: $viewModel.appError) { appAlert in
             Alert(title: Text("Error"),
                   message: Text("""
                     \(appAlert.errorString)
                     Please try again later!
                     """
                     )
             )
         }

         .ignoresSafeArea(.all)
}

}

enum ViewStateDashboard { case START case LOADING case SUCCESS(dashboardModel: Dashboard) case FAILURE(error: String) }

protocol FetchDashboardDataFromServer { func getDashboardData() var currentState: ViewStateDashboard { get set } }

class DashboardViewModel: ObservableObject, FetchDashboardDataFromServer {

struct AppError: Identifiable {
    let id = UUID().uuidString
    let errorString: String
}

@Published var appError: AppError?

let monitor = NWPathMonitor()
let monitorPostUser = NWPathMonitor()

let queue = DispatchQueue(label: "InternetConnectionMonitor")

var cancelable: Set<AnyCancellable> = []
@Published var currentState: ViewStateDashboard = .START

init() {
    self.currentState = .LOADING
}


// GET Method
func getDashboardData() {
    print("fetch dashboard data")
    self.currentState = .LOADING
    monitor.pathUpdateHandler = { pathUpdateHandler in
        if pathUpdateHandler.status == .satisfied {

            APIClient.dispatch(
                APIRouter.GetDashboardData(queryParams:
                APIParameters.GetDasbhboardParams(apikey: "API_KEY")))
            .sink { completion in
                switch completion {
                case .finished:
                    print("Execution Finihsed dashboard.")
                case .failure(let error):
                    DispatchQueue.main.async {
                        print("dashboard error", error)
                        self.appError = AppError(errorString: error.localizedDescription)
                        self.currentState = .FAILURE(error: error.localizedDescription)
                    }
                }
            }
        receiveValue: {  dashboardData in
            print("received dashboard data", dashboardData)
            self.currentState = .SUCCESS(dashboardModel: dashboardData)
        }.store(in: &self.cancelable)

        } else {
            DispatchQueue.main.async {
                self.currentState = .FAILURE(error: StringConstants.NoInterNet)
                self.appError = AppError(errorString: StringConstants.NoInterNet)
                print("no internet get users")
            }
        }
    }
    monitor.start(queue: queue)

}

}

What could be the issue here? Any help would be appreciated.


Solution

  • When you close the alert, viewModel.appError is set to nil. If you want it to appear again, you must set it to a value again.