Как передать объект среды между родственными представлениями?

#swift #swiftui #swiftui-environment

Вопрос:

Я пытаюсь передать некоторые данные между родственными представлениями.

У меня есть VerseDetailView кнопка с кнопкой:

 @StateObject var favoritesViewModel = FavoritesViewModel()
...
Button("Add to favorite") {
 favoritesViewModel.add(verse: verse)
}
 

Моя FavoritesViewModel внешность выглядит так:

 class FavoritesViewModel: ObservableObject {
    
    @Published var favoriteVerses: [Verse] = []
    
    func add(verse: Verse) {
        favoriteVerses.append(verse)
    }
    
}
 

Как бы я перешел favoriteVerses к отображению в совершенно другом подвиде?

Мой основной файл приложения выглядит так:

 var body: some Scene {
        WindowGroup {
            TabView {
                NavigationView {
                    BookView() // VerseDetailView is a child of this view
                }
                .tabItem {
                    Image(systemName: "book")
                    Text("Books")
                       
                }
                NavigationView {
                    FavoritesView() // I want to get the array of favoriteVerses here
                }
                
                .tabItem {
                    Image(systemName: "bookmark")
                    Text("Favorites")
                }
            }
        }
    }
 

Моя FavoritesView внешность выглядит так:

 struct FavoritesView: View {
    @EnvironmentObject var favoritesViewModel: FavoritesViewModel 
     // is this correct?
    // I get a hread 1: "Fatal error: No ObservableObject of type FavoritesViewModel found" error
    
    var body: some View {
        
            List {
                Section(header: Text("Favorite verses")) {
                    ForEach(favoritesViewModel.favoriteVerses) { verse in
                        Text(verse.verse)
                    }
                }
                
            }
    }
    
}
 

Я попытался добавить это в верхней части основного файла приложения:

 var favoritesViewModel = FavoritesViewModel()
...
NavigationView { 
  FavoritesView().environmentObject(favoritesViewModel)
}
 

Но это тоже не работает

Ответ №1:

Добавьте его для общего вида сверху (в вашем случае это так TabView ), например

 TabView {
    NavigationView {
        BookView() // VerseDetailView is a child of this view
    }
    .tabItem {
        Image(systemName: "book")
        Text("Books")
           
    }
    NavigationView {
        FavoritesView() // I want to get the array of favoriteVerses here
    }
    
    .tabItem {
        Image(systemName: "bookmark")
        Text("Favorites")
    }
}
.environmentObject(favoritesViewModel)   // << here !!
 

Комментарии:

1. По-прежнему ничего.. когда я перехожу на другую вкладку, она полностью пуста. var favoritesViewModel = FavoritesViewModel() Все еще должен быть наверху? Может ли это быть что-то с повторным уничтожением представления, поэтому список стихов не отображается? С другой стороны, я больше не получаю фатальной ошибки, но список все еще пуст

2. это звучит как другая проблема — как будто вы создаете разные модели в разных представлениях

3. Должен ли я по-прежнему иметь @StateObject var favoritesViewModel = FavoritesViewModel() в своем VerseDetailView и в сцене делегата var favoritesViewModel = FavoritesViewModel() ?

4. Нет, вам нужно создать только один делегат сцены — во всех остальных местах доступ к нему через @EnvironmentObject оболочку.

Ответ №2:

Вы можете передать объект environmentObject в каждое представление следующим образом:

 TabView {
NavigationView {
    BookView() // VerseDetailView is a child of this view
}
.tabItem {
    Image(systemName: "book")
    Text("Books")
       
}
.environmentObject(favoritesViewModel)

NavigationView {
    FavoritesView() // I want to get the array of favoriteVerses here
}
.tabItem {
    Image(systemName: "bookmark")
    Text("Favorites")
}
.environmentObject(favoritesViewModel)

}