SwiftUI: не удается получить доступ к @EnvironmentObject в модели представления

#core-data #mvvm #swiftui #viewmodel #combine

Вопрос:

Я создаю приложение с помощью SwiftUI / Combine и пытаюсь сделать это по шаблону MVVM. Я немного запутываюсь в том, как лучше всего раскрывать определенные свойства и, в частности, в отношении реализации основных данных.

В главном файле приложения я настроил объект environmentnt следующим образом (я объясню, почему позже).:

 struct Football_GuruApp: App {  let persistenceController = PersistenceController.shared  @StateObject var favouritePlayers = FavouritePlayersViewModel()   var body: some Scene {  WindowGroup {  ContentView()  .environment(.managedObjectContext, persistenceController.container.viewContext)  .environmentObject(favouritePlayers)  }  } }  

Приложение имеет 3 основных вида:

Представление содержимого: содержит представление вкладок с 2 подвидами: FetchedResultsView() и FavoritesView()

FetchedResultsView: это содержит вложенное представление FetchedPlayers (), которое выглядит следующим образом:

 struct FetchedPlayersView: View {  @EnvironmentObject var fetchedResultsVM: FetchedResultsViewModel    var body: some View {  Section(header: Text("Players")) {  ForEach(fetchedResultsVM.fetchedPlayers, content: { player in  PlayerView(player: player)  })    if fetchedResultsVM.playersExpandable {  MoreResultsButton(action: fetchedResultsVM.getMorePlayers, buttonTitle: "More players")  }  }  } }  

И, наконец, избранное:

 struct FavouritesView: View {  @EnvironmentObject var favouritePlayersVM: FavouritePlayersViewModel  var context = PersistenceController.shared.container.viewContext    var body: some View {  List {  ForEach(context.fetchAll(PlayerCD.self)) { player in  PlayerView(player: PlayerViewModel.mapFromCoreData(player: player))  }  }  } }  

Внутри PlayerView() (подвида FetchedPlayersView) у нас есть кнопка:

 FavouritesButton(playerViewModel: player)  

When tapped we set a property on the PlayerViewModel to true:

 playerViewModel.favourite = true  

And then a didSet method on PlayerViewModel triggers the player to be stored to core data:

 var favourite = false {  didSet {  self.mapToCoreData()  } }   func mapToCoreData() {  let storedPlayer = PlayerCD(context: context)    storedPlayer.id = self.id  storedPlayer.firstName = self.firstName  storedPlayer.secondName = self.secondName    try? PersistenceController.shared.container.viewContext.save()  favouritePlayersVM.updateFavourites()  }  

We have the following env object on the PlayerViewModel

 @EnvironmentObject var favouritePlayersVM: FavouritePlayersViewModel  

Наконец, FavoritepLayersvIewмОдель выглядит следующим образом:

 class FavouritePlayersViewModel: ObservableObject {  @Published var players = [PlayerViewModel]()  func updateFavourites() {  let context = PersistenceController.shared.container.viewContext  let savedPlayers = context.fetchAll(PlayerCD.self)  self.players = [PlayersViewModel]()    savedPlayers.forEach {  players.append(PlayerViewModel.mapFromCoreData(player: $0))  }  } }  

Таким образом, идея заключается в том, что при нажатии кнопки мы сохраняем основные данные, а затем одновременно обновляем список игроков в FavoritepLayersvIewмОдель, которая затем должна обновить список избранных последними игроками. Тем не менее, очевидно, что я борюсь с реализацией объекта окружающей среды. Я думал, что, открыв это в корне приложения, я смогу получить доступ везде, но я предполагаю, что, поскольку, например, PlayerViewModel не является прямым потомком, я не могу получить доступ (так как я получаю сбой).

Возможно, использование объекта env здесь не подходит, но я изо всех сил пытаюсь понять, как лучше всего его использовать, чтобы я мог обновить список игроков favoritesviewmodel из PlayerViewModel, используя тот же экземпляр этой модели favoritesviewmodel для обновления избранного.

По той же причине я также не могу получить доступ к NSManagedObjectContext, который я установил как @Environment в корневом файле в моделях представлений, поэтому я использую одноэлементный постоянный контейнер для хранения своих основных данных, что на самом деле я не хотел делать.

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

1. Что касается последнего абзаца, вы должны вставить текст NSManagedObjectContext в модели представлений и сделать это уже при создании моделей представлений.

2. Хорошо, большое спасибо — вы имеете в виду в начале, верно? В этом случае, возможно, то же самое будет работать для модели favoriteplayersviewmodel?

3. Все модели просмотра, которые в этом нуждаются.