Video Link Youtube
ConsoleError
Fatal error: No ObservableObject of type UserDefaultsConfig found. A View.environmentObject(_:) for UserDefaultsConfig may be missing as an ancestor of this view.: file SwiftUI, line 0
UserDefaults Config
class UserDefaultsConfig: ObservableObject {
@Published var allFavoriteMovie: [PopularMovie] = []
let defaults = UserDefaults.standard
func setUserDefaults(value: PopularMovie) {
let encoder = JSONEncoder()
if let encoded = try? encoder.encode(value) {
defaults.set(encoded, forKey: "favoriteMovie")
}
if let savedFavoriteMovie = defaults.object(forKey: "favoriteMovie") as? Data {
let decoder = JSONDecoder()
if let loadedFavMovie = try? decoder.decode(PopularMovie.self, from: savedFavoriteMovie) {
allFavoriteMovie.append(loadedFavMovie)
print("favMovie: \(allFavoriteMovie)")
}
}
}
}
CustomTabView opens first
CustomTabView
TabView(selection: $selectedTab) {
MainView(searchMovie: SearchMovieVM(), mainVM: MainVM())
.ignoresSafeArea()
.tag(TabCategory.movieList)
FavoriteView()
.ignoresSafeArea()
.tag(TabCategory.favorite)
}
I click on MovieCell in MainView and direct it to DetailView.
MainView
NavigationLink(
destination: DetailView(movie: .constant(mainVM.popularMovie[movie])),
label: {
MovieCell(popularMovie: .constant(mainVM.popularMovie[movie]))
.foregroundColor(Color(UIColor.label))
})
DetailView
When I clicked the button here, setUserDefaults function in userDefaultsConfig was running.
struct DetailView: View {
....
@StateObject var userDefaultsConfig = UserDefaultsConfig()
var body: some View {
ZStack {
.....
ScrollView(.vertical, showsIndicators: false) {
.....
HStack {
Spacer()
Button(action: { self.userDefaultsConfig.setUserDefaults(value: movie) }) {
Image(systemName: "suit.heart")
.imageScale(.large)
.foregroundColor(.red)
}
}
....
}
.padding(.horizontal)
}
}
.environmentObject(userDefaultsConfig)
}
}
The movie saved in UserDefaults on the DetailView page will be shown on the Favorites page, but when I open the Favorites page, I get an error.
FavoritesView
struct FavoriteView: View {
@EnvironmentObject var userDefaultsConfig: UserDefaultsConfig
var body: some View {
VStack {
// ForEach(userDefaultsConfig.allFavoriteMovie, id: \.id) { item in
// Text(item.title ?? "")
// }
Text("")
.onAppear {
print(self.userDefaultsConfig.allFavoriteMovie)
}
}
}
}
You need to place state object in CustomTabView
, like
struct CustomTabView: View {
....
@StateObject var userDefaultsConfig = UserDefaultsConfig()
...
TabView(selection: $selectedTab) {
MainView(searchMovie: SearchMovieVM(), mainVM: MainVM())
.ignoresSafeArea()
.tag(TabCategory.movieList)
FavoriteView()
.ignoresSafeArea()
.tag(TabCategory.favorite)
}
.environmentObject(userDefaultsConfig) // << here !!
...
and in DetailView
just use it as environment object, same as you do in FavoriteView
, ie.
struct DetailView: View {
@EnvironmentObject var userDefaultsConfig: UserDefaultsConfig
...
}