Learn Courses My Dashboard

Running into issues with AppStorage

Hey all

I am currently working on the recipes app but wanted to add some additional features. One feature that im adding (I didn’t finish the course, though I didn’t see it as a topic) is a favorites section. I have the ability to add favorites to another view, but the changes won’t stay when the app is terminated.

I tried AppStorage but I guess I am implementing it incorrectly.

Recipe Model:

class Recipe: Identifiable, Decodable {
    
    var id:UUID?
    var name:String
    var featured:Bool
    var isFavorite: Bool
    var image:String
    var imageURL: URL?
    var description:String
    var tag: String
    var tag1: String
    var prepTime:String
    var cookTime:String
    var totalTime:String
    var servings:Int
    var highlights:[String]
    var calories: String?
    var satFat: String?
    var sugar: String?
    var protein: String?
    var sodium: String?
    var fat: String?
    var carbs: String?
    var dietaryFiber: String?
    var cholesterol: String?
    var ingredients:[Ingredient]
    var directions:[String]
}

ButtonView:

import SwiftUI

struct FavoriteButton: View {
    
@Binding var isSet: Bool
    
    var body: some View {
        Button {
            isSet.toggle()
        
        } label: {

            Image(systemName: isSet ? "heart.fill" : "heart")
                .font(.title2)
                .labelStyle(.iconOnly)
                .foregroundColor(isSet ? .red : .pink )
                .cornerRadius(10)
                .animation(.easeInOut(duration: 0.5))
        }
        
        

    }
}

FavoritesView:

import SwiftUI

struct FavoriteListView: View {
    
    @EnvironmentObject var model:RecipeModel
    @State private var showFavoritesOnly = true
    @AppStorage("isFavorite") var isFavorite = false

    var filteredRecipe: [Recipe] {
        model.recipes.filter { favorites in
            (!showFavoritesOnly || favorites.isFavorite)
        }
    }
    
    var body: some View {
        NavigationView {
            
            
            
            ScrollView {
                LazyVStack(alignment: .leading) {
                    Toggle(isOn: $isFavorite) {
                        Text("Favorites only")
                    }.opacity(0.0)
                
                    ForEach(filteredRecipe) { items in
                        NavigationLink(destination: {
                            RecipeDetailView(recipe: items, isSet: showFavoritesOnly)
                        }, label: {
                          
                                    Image(items.image)
                                        .resizable()
                                        .scaledToFit()
                                        .frame(width: 75, height: 50)
                                        .cornerRadius(10)
                          
                            VStack(alignment: .leading) {
                                
                                HStack {
                                    Text(items.name)
                                        .font(.caption)
                                        .foregroundColor(.black)
                                        .lineLimit(1)
                                    Spacer()
                                    Image(systemName: "chevron.right")
                                        .padding()
                             
                                }
                            }
                        })
                    }.listStyle(.grouped)
                }
                
                .padding()
            }.navigationTitle("Favorite Recipes")

I currently have a default of 4 recipes marked as favorites in the JSON file. When I mark other recipes as favorites, or even mark it as unfavorite, it works. But when I terminate and reopen the app, it goes back to the default. Sorry if this is a silly question but not entirely sure if I am using AppStorage properly here or even saving the wrong values.

I appreciate any help and absolutely love this community.

The problem you’ve got at the moment is that there is no simple way of identifying the Recipe item that you have marked as a Favourite in AppStorage. Ideally you need to have a fixed id or each recipe and store the id’s that are favourited in an array in AppStorage. At the moment the id’s are assigned as a UUID each time you run the App so they are dynamic and change each time the App is loaded so you cannot use the id property as it is currently configured.

What you COULD do is change the id to be an Int and not be optional. ie:

class Recipe: Identifiable, Decodable {
    
    var id:Int
    var name: String
    var featured:Bool
    var isFavorite: Bool
    var image:String
    var imageURL: URL?
    var description:String
    var tag: String
    var tag1: String
    var prepTime:String
    var cookTime:String
    var totalTime:String
    var servings:Int
    var highlights:[String]
    var calories: String?
    var satFat: String?
    var sugar: String?
    var protein: String?
    var sodium: String?
    var fat: String?
    var carbs: String?
    var dietaryFiber: String?
    var cholesterol: String?
    var ingredients:[Ingredient]
    var directions:[String]
}

Then go through all your json data and add an id parameter to each of your Recipes.

First recipe item:

"id": 1

Second recipe item:

"id": 2

and so on.

When you initially load your json you would need to loop through the recipes and add each id to the AppStorage array where each isFavorite is true (caters for the defaults you have set) but only add the id to AppStorage if the id does not already exist in that array.

Then you need to loop through the AppStorage array and set any recipe item isFavorite to true where the id exists in that array (caters for the ones you have favourited that were not defaulted in the json data).

I hope that makes sense.