I’m having an issue with my FavoritesTab. It’s a bit difficult to explain so I posted a video to show what’s the ongoing issue. In short, once I favorite a character, and go to the FavoritesTab, it will display a duplicate. Then trying to switch back and forth between tabs will remove the display and then (again) finally will display appropriately. Please let me know if you need any additional code
I have environmentObject modifiers of my ViewModel and Favorites on CharactersTabView which is the @Main entry view for my app.
struct CharactersTabView: View {
var body: some View {
TabView {
//MARK: - Character Tab
CharacterView()
.tabItem {
Label("Characters", systemImage: "person.3.fill")
}
//MARK: - Favorites Tab
FavoritesView()
.tabItem {
Label("Favorites", systemImage: "heart.fill")
}
}//TabView
}
}
Here is my Favorites code
class Favorites: ObservableObject {
private var characters: Set<String>
private let saveKey = "SaveFavorites"
init(){
//load saved data
if let data = UserDefaults.standard.data(forKey: saveKey) {
//Using Set<String> because we don't want to store the entire struct, just the id
if let decoded = try? JSONDecoder().decode(Set<String>.self, from: data) {
characters = decoded
return
}
}
characters = []
}
func contains(_ character: Character) -> Bool {
characters.contains(String(character.id))
}
func add(_ character: Character) {
objectWillChange.send()
characters.insert(String(character.id))
save()
}
func remove(_ character: Character) {
objectWillChange.send()
characters.remove(String(character.id))
save()
}
func save(){
if let encoded = try? JSONEncoder().encode(characters) {
UserDefaults.standard.set(encoded, forKey: saveKey)
}
}
}
And here is my FavoritesView
struct FavoritesView: View {
@EnvironmentObject var model: CharacterViewModel
@EnvironmentObject var favorites: Favorites
//Creating the property of the same type (Favorites) can access the data and get updated when the data changes
var body: some View {
NavigationView {
List(model.filteredCharacters) { character in
if favorites.contains(character) {
NavigationLink {
CharacterDetailsView(character: character)
} label: {
HStack {
CharacterRowView(imageUrlString: character.image, name: character.name, species: character.species)
}
}
}
}
.navigationTitle("Favorites")
}
}
}
Here is my other TabView of Character for reference
struct CharacterView: View {
@EnvironmentObject var model: CharacterViewModel
@EnvironmentObject var favorites: Favorites
//Creating the property of the same type (Favorites) can access the data and get updated when the data changes
//MARK: - Body
var body: some View {
NavigationView {
List(model.filteredCharacters){
character in
NavigationLink {
CharacterDetailsView(character: character)
} label: {
HStack{
CharacterRowView(imageUrlString: character.image, name: character.name, species: character.species)
if favorites.contains(character) {
Spacer()
Image(systemName: "heart.fill")
.accessibilityLabel("This is a favorite character")
.foregroundColor(.red)
}
}
}
}
.searchable(text: $model.searchText, prompt: "Search for a character")
.onChange(of: model.searchText, perform: { newValue in
Task {
await model.fetchallCharacters()
}
})
.navigationBarTitle("Characters")
}//Navigationview
.task({
await model.fetchallCharacters()
})
.phoneOnlyNavigationView()
}
}