#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. Все модели просмотра, которые в этом нуждаются.