view automatically pop to previous view in swift ui due to view model is observed from tabview to inside multiple view?

Viewed 269

I am facing an issue while pushing 1 view to another view. Let me explain the hierarchy.

ContentView -> 2 tabs, TabAView and TabBView Inside TabBView. There is 1 view used ConnectView: Where is a Button to connect. After tapping on the button of Connect, the user move to another View which is called as UserAppView.

Here is the code to understand better my problem.

ContentView.swift

struct ContentView: View {
    enum AppPage: Int {
        case TabA=0, TabB=1
    }
    
    @StateObject var settings = Settings()
    @ObservedObject var userViewModel: UserViewModel
    @ObservedObject var userAppViewModel: UserAppViewModel
    
    var body: some View {
        NavigationView {
            TabView(selection: $settings.tabItem) {
                TabAView(userViewModel: userViewModel, userAppViewModel: userAppViewModel)
                    .tabItem {
                        Text("TabA")
                    }
                    .tag(AppPage.TabA)
                
                TabBView(userViewModel: userViewModel, userAppViewModel: userAppViewModel)
                    .tabItem {
                        Text("Apps")
                    }
                    .tag(AppPage.TabB)
            }
            .accentColor(.white)
            .edgesIgnoringSafeArea(.top)
            .onAppear(perform: {
                settings.tabItem = .TabA
            })
            .navigationBarTitleDisplayMode(.inline)
        }
        .environmentObject(settings)
    }
}

This is TabAView:

 struct TabAView: View {
    
    @ObservedObject var userViewModel: UserViewModel
    @ObservedObject var userAppViewModel: UserAppViewModel
    @EnvironmentObject var settings: Settings
    
    init(userViewModel: UserViewModel, userAppViewModel: UserAppViewModel) {
        self.userViewModel = userViewModel
        self.userAppViewModel =  userAppViewModel
    }
    
    var body: some View {
        Vstack {
            /// code
        }
        .onAppear(perform: {
            /// code
        })
        .environmentObject(settings)
    }
}

This is another TabBView:

struct TabBView: View {
    
    @ObservedObject var userViewModel: UserViewModel
    @ObservedObject var userAppViewModel: UserAppViewModel
    
    init(userViewModel: UserViewModel, userAppViewModel: UserAppViewModel) {
        self.userViewModel = userViewModel
        self.userAppViewModel =  userAppViewModel
    }
    
    var body: some View {
        VStack (spacing: 10) {
            NavigationLink(destination: ConnectView(viewModel: ConnectViewModel(id: id!), userViewModel: userViewModel, userAppViewModel: userAppViewModel)) {
                UserCardWidget()
            }
        }
    }
}

There is 1 connectView used on the TabBView through which the user will connect. ConnectViewModel is used here to call connect API.

class ConnectViewModel: ObservableObject {
    
    var id: String?
    
    init(id: String) {
        self.id = id
    }
    
    func connect(completion: @escaping () -> Void) {
        APIService.shared.connectApp(id: self.id!) { connected in
            DispatchQueue.main.async {
                self.isConnected = connected ?? false
                completion()
            }
        }
    }
}

This is connect view

struct ConnectView: View {
    
    @ObservedObject var connectViewModel: ConnectViewModel
    @ObservedObject var userViewModel: UserViewModel
    @ObservedObject var userAppViewModel: UserAppViewModel
    @State var buttonTitle = "CONNECT WITH THIS"
    @State var isShowingDetailView = false
    
    var body: some View {
        VStack {
            Spacer()
            if let id = connectViewModel.id {
                NavigationLink(destination: UserAppView(id: id, userAppViewModel: userAppViewModel, userViewModel: userViewModel), isActive: $isShowingDetailView) {
                    Button(buttonTitle, action: {
                        connectViewModel.connect {
                            buttonTitle = "CONNECTED"
                            isShowingDetailView = true
                        }
                    })
                }
            }
        }
    }
}

This is the UserAppViewModel where API is hit to fetch some user-related details:

class UserAppViewModel: ObservableObject {

var id = ""
func getdetails() {
    APIService.shared.getDetails() { userDetails in
        DispatchQueue.main.async {
            /// code
        }
    }
}

}

This is UserAppView class

struct UserAppView: View {
    
    @ObservedObject var userViewModel: UserViewModel
    @ObservedObject var userAppViewModel: UserAppViewModel
    
    init(id: String, userAppViewModel: UserAppViewModel, userViewModel: UserViewModel) {
        self.id = id
        self.userAppViewModel = userAppViewModel
        self.userViewModel = userViewModel
    }
    
    var body: some View {
        
        VStack {
            Text(userAppViewModel.status)
        }.onAppear(perform: {
            **userAppViewModel.getDetails**(id: id)
            
        })
    }
    
}

Whenever this statement userAppViewModel.getDetails executes, the user comes to UserAppView but when the response of getDetails is received, it automatically goes to ConnectView.

I have removed most of the code from a confidential point of view but this code will explain the reason and error. Please look into the code and help me.

0 Answers
Related