0

So this is a simplified version of my app which have I tried that reproduces the error, I have a TabView with 2 Tabs(HomeView &OrderView), if I placed the selection index using viewModel, everytime I go to OrderView and return back to HomeView, the loaded view in HomeView will be gone, this goes the same for all and any other views in other tabs.

There is no error log whatsoever in the debugging logs, the API fetch perfectly and the data is there if I print them, the variables is all fine too, but the UI only appearing at first load (before switching tab), then it is gone after I switch tab.

If I removed the tab selection index or placed the index in the ContentView with @State, it all works perfectly, but I need to put the index in ViewModel so I can modify the index from another View.

What is wrong with this behaviour? Thank you very much in advance

ContentView.swift

struct ContentView: View {
    @Environment(\.managedObjectContext) private var viewContext
    @ObservedObject var viewModel = HomeViewModel()

    var body: some View {
        NavigationView {
            TabView(selection: self.$viewModel.homeTabSelected) {
                HomeView(homeVm: self.viewModel).tabItem {
                    VStack {
                        Image(systemName: "house")
                        Text("Home")
                    }
                }.tag(0)
                
                OrderView().tabItem {
                    VStack {
                        Image(systemName: "note.text")
                        Text("Order")
                    }
                }.tag(1)
            }
        }
    }
}

HomeViewModel.swift

class HomeViewModel: ObservableObject {
    @Published var homeTabSelected = 0
    
    func changeTab() {
        self.homeTabSelected = 2
    }
}

HomeView.swift

struct HomeView: View {
    @ObservedObject var homeVm: HomeViewModel
    
    var body: some View {
        ZStack {
            VStack {
                ScrollView {
                    VStack(alignment: .leading) {
                        ZStack(alignment: .top) {
                            
                            VStack(alignment: .leading) {
                                HStack {
                                    Text("Good Afternoon")
                                        .foregroundColor(Color.white)
                                }
                                
                                Spacer().frame(height: 25)
                                
                            }.offset(y: 50)
                            .frame(maxWidth: .infinity, alignment: .topLeading)
                            .padding(.horizontal, 20)
                            
                        }
                        
                        Group {
                            MenuListView(homeVm: self.homeVm)
                        }
                    }
                }
            }.edgesIgnoringSafeArea(.top)
            
        }.navigationBarHidden(true)
        .background(Color("c_fff"))
    }
}

MenuListView.swift

struct MenuListView: View {
    @ObservedObject var viewModel = MenuListViewModel()
    @ObservedObject var homeVm: HomeViewModel
    
    var body: some View {
        VStack {
            
            Group {
                VStack(alignment: .leading) {
                    ScrollView(.horizontal, showsIndicators: false) {
                        HStack {
                            ForEach(self.viewModel.category, id: \.self) { cat in
                                Button(action: {
                                }) {
                                    Text(cat.categoryTitle.capitalized)
                                        .padding(.horizontal, 15)
                                        .padding(.vertical, 8)

                                    // This will not appear after I changed tab and return to HomeView
                            }
                        }
                    }
                }
            }
        }
        .onAppear {
            self.viewModel.getMenuList()
        }
    }
}

MenuListViewModel.swift

import Combine
import SwiftUI

class MenuListViewModel: ObservableObject, ModelService {
    var apiSession: APIService
    @Published var menu = [MenuListItem]()
    @Published var category = [CategoryListItem]()
    @Published var promo = [HomePromo]()
    @Published var categorySelected = "promo"
    
    var cancellables = Set<AnyCancellable>()
    
    init(apiSession: APIService = APISession()) {
        self.apiSession = apiSession
    }
    
    func getMenuList() {
        let cancellable = self.getMenuList()
            .sink(receiveCompletion: { result in
                switch result {
                case .failure(let error):
                    print("Handle error menu: \(error)")
                case .finished:
                    break
                }
                
            }) { (menu) in
                self.menu = menu.products
                self.category = menu.category
                self.promo = menu.promos
        }
        cancellables.insert(cancellable)
    }
    
    
}

before

after

so as I have screenshot, at first app start, the the data is loaded and properly loaded in the View, then if I click on the second tab, and go back to first tab, the view is gone (the data & all variables loaded correctly in the log, also no error log whatsoever)

Charas
  • 1,753
  • 4
  • 21
  • 53
  • This isn't a [Minimal, Reproducible Example](https://stackoverflow.com/help/minimal-reproducible-example), but I think the issue is that you are passing the `HomeViewModel` which has been declared as an` ObservedObject` to another view where `HomeViewModel` which has been declared as an` ObservedObject`. Then you are trying to pass it again as an ObservedObject. See: [Passing An ObservedObject To Nested Child Views SwiftUI (SwiftUI Data Flow)](https://stackoverflow.com/questions/57551220/passing-an-observedobject-to-nested-child-views-swiftui-swiftui-data-flow). – Yrb Aug 03 '21 at 18:34
  • Thanks for the answer, yes, sorry it isn't minimal reproducible example, should have put the api fetch, so what is the correct way to properly share a variable so that I can change the tabview selection index from another subview? – Charas Aug 03 '21 at 18:40
  • I have tried using UserDefaults, but when I change the tab index from another view, the main view is not being updated (changed to the tab index specified) – Charas Aug 03 '21 at 18:42
  • Make a minimal, reproducible example and we can play with it. Otherwise, see the question I cited. – Yrb Aug 03 '21 at 18:43
  • Switch all of the ones that look like this `@ObservedObject var viewModel = HomeViewModel()` to `@StateObject var viewModel = HomeViewModel()` – lorem ipsum Aug 03 '21 at 18:51

0 Answers0