swiftuiswiftui-environment

Trouble using @environmentObject and @StateObject


I am creating my first app and I am having trouble using @EnvironmentObject and @StateObject. When I run the simulator it opens my ContentView(). I am trying to get it to where it opens the MainView(), which has a tabView. And now the tabView is not showing my ContentView(). I am assuming I have the @EnvironmentObject and @StateObject in the wrong places. In my ContentView it shows a list and addButton. I am basically trying to have a program that is updated by the user by filling out a form.

Here is the Main Method

import SwiftUI

@main
struct Location_ScoutApp: App {
    
   @StateObject var listViewModels: ListViewModel = ListViewModel()
    
    var body: some Scene {
        WindowGroup {
          //  MainView(){
               ContentView()
            .environmentObject(listViewModels)
            //}
        }
    }
}

Here is my MainView.

import SwiftUI

struct MainView: View {
    
    var body: some View {
        
        TabView {
            MapView()
                .tabItem {
                    Label("Map", systemImage: "map.circle")
                }
// this is where i am having trouble.
            ContentView()
                .tabItem {
                    Label("Explore", systemImage: "magnifyingglass")
                
            }
            
            ProfileView()
                .tabItem {
                    Label("Profile", systemImage: "person.crop.circle")
                }
        }
    }

}
struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()

    }
}

Here is my ContentView:

import SwiftUI

struct ContentView: View {
    @EnvironmentObject var listViewModel: ListViewModel
    
    var body: some View {
        List {
            ForEach(listViewModel.items) { item in
// this is where i am getting my new error.
                ListRowView(item: item)
                    .onTapGesture {
                        listViewModel.updateItem(item: item)
                    }
                
            }
        }
        
        .navigationTitle("Explore")
        .navigationBarItems(
            leading: EditButton(),
            trailing:
                NavigationLink("Add", destination: addALandmarkForm()))
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        NavigationView {
        ContentView()
    }
        .environmentObject(ListViewModel())
    }
}

Solution

  • Without a reproducible example, it's hard to debug. This code, however, which is based on yours, works fine. Perhaps you can find the difference between your implementation and mine:

    
    struct Item : Identifiable {
        var id = UUID()
        var title : String
    }
    
    class ListViewModel: ObservableObject {
        @Published var items : [Item] = [.init(title: "Test 1"),.init(title: "Test 2")]
    }
    
    @main
    struct Location_ScoutApp: App {
        
       @StateObject var listViewModels: ListViewModel = ListViewModel()
        
        var body: some Scene {
            WindowGroup {
              MainView()
                .environmentObject(listViewModels)
            }
        }
    }
    
    struct MainView: View {
        
        var body: some View {
            
            TabView {
                Text("Map")
                    .tabItem {
                        Label("Map", systemImage: "map.circle")
                    }
    
                ContentView()
                    .tabItem {
                        Label("Explore", systemImage: "magnifyingglass")
                    
                }
                
                Text("profile")
                    .tabItem {
                        Label("Profile", systemImage: "person.crop.circle")
                    }
            }
        }
    
    }
    
    struct ContentView: View {
        @EnvironmentObject var listViewModel: ListViewModel
        
        var body: some View {
            NavigationView {
               List {
                 ForEach(listViewModel.items) { item in
                     Text(item.title)
                 }
               }
               .navigationTitle("Explore")
            }
        }
    }