Passing binding through Navigation Link crashes the app

48 views Asked by At

Here is the navigation stack

All recipes > specific recipe > ingredients > specific ingredient

All recipes View

struct RecipesScreen: View {
    @EnvironmentObject var sessionData: SessionData
    
    
    var body: some View {
        NavigationStack {
            List() {
                ForEach($sessionData.familyData.familyRecipes, id: \.self) { $recipe in
                    NavigationLink {
                        EditRecipeScreen(recipe: $recipe)
                    } label: {
                        Text("\(recipe.originalRecipe.title)")
                    }
                }
            }
        }
    }
}

Specific recipe View

struct EditRecipeScreen: View {
    @Binding var recipe: FamilyRecipe
    @EnvironmentObject var sessionData: SessionData
    
    var body: some View {
        List {
            // title
            TextField("Title", text: $recipe.originalRecipe.title)
            
            // ingredients >
            NavigationLink {
                IngredientsList(ingredients: $recipe.originalRecipe.ingredients)
            } label: {
                Text("Ingredients")
            }

            // cook >
            NavigationLink {
                InstructionsNavigation(instructions: $recipe.originalRecipe.cookInstructions, minutes: $recipe.originalRecipe.minutesToCook, type: "cook")
            } label: {
                Text("Cooking steps")
            }
            
        }
    }
}

Ingredients View

struct IngredientsList: View {
    @EnvironmentObject var sessionData: SessionData
    @Binding var ingredients: [RecipeIngredient]
    
    var body: some View {
        
        List {
            ForEach($ingredients, id: \.ingredient.id) { $recipeIngredient in
                NavigationLink {
                    IngredientView(recipeIngredient: $recipeIngredient)
                } label: {
                    HStack {
                        Text(recipeIngredient.ingredient.displayName)
                        Spacer()
                        Text("\(recipeIngredient.amount.removeZerosFromEnd()) \(recipeIngredient.measure.description)")
                    }
                }
            }
        }
    }
}

Specific ingredient View

struct IngredientView: View {
    @Binding var recipeIngredient: RecipeIngredient
    
    var body: some View {

            Text("\(recipeIngredient.ingredient.displayName)")
            Text(recipeIngredient.ingredient.measure.description)

    }
}

This is a simplified version of the code but everything works up to the point where I tap on the navigation link to take me to the Specific ingredient view and my phone crashes.

If I place the 2 text fields from the Specific Ingredient View directly in the navigation link then it does not crash.

Another, possibly important, piece of information is that when it crashes the crash doesn't show in Xcode, my phone just freezes and I can no longer interact with the app but it remains open on the phone and Xcode shows nothing in the logs.

If I change the recipeIngredient variable in the Specific Ingredient View to a @State and pass it in without binding, it also works. But I pass through a binding through a navigation link from the all recipes view, so can't figure out why it's not working. I need the binding as I need to update the original ingredient in each case.

Any help would be so appreciated, thank you.

1

There are 1 answers

0
malhal On

id: \.self is a mistake you must supply a real id to the ForEach or it'll crash as you experience. A simple way to fix this is make your model struct conform to Identifiable then you don't need to supply an id param.