Apologies because I'm new to SwiftUI -
I have a class (Meal) that contains an array of objects of another class (Food). What I'm trying to achieve here is to be able to add foods and have that update in a list, and then to be able to edit an individual food by tapping on it.
I'm iterating through the list of foods and using each food to (1) create a NavigationLink and (2) simply list the food's name in the list. The problem is that I get the error Initializer 'init(_:)' requires that 'Binding<String>' conform to 'StringProtocol'
when I try to reference the food in an "unbound" way. Specifically, in the code below, it's at the line Text(food.name)
.
ForEach($meal.foods) { food in
NavigationLink(destination: FoodView(food: food)) {
Text(food.name)
}
}
I'm aware I could iterate through a list of indices instead (I think) but I think that's probably bad practice. I'm trying to figure out what the best practice is in this scenario. Thanks in advance!
Full code below:
// MARK: Views
struct ContentView: View {
@State private var day = Day()
var body: some View {
MealView(meal: $day.meals.first!)
}
}
struct MealView: View {
@Binding var meal: Meal
var body: some View {
NavigationStack {
List {
ForEach($meal.foods) { food in
NavigationLink(destination: FoodView(food: food)) {
Text(food.name)
}
}
}
}
}
}
struct FoodView: View {
@Binding var food: Food
var body: some View {
VStack {
TextField("Food", text: $food.name)
}
}
}
// MARK: Data
class Day {
var meals: [Meal] = [Meal()]
}
@Observable
class Meal: Identifiable {
var id: UUID = UUID()
var foods: [Food] = [Food(name: "Pizza"), Food(name: "Pasta"), Food(name: "Steak")]
}
@Observable
class Food: Identifiable {
var id: UUID = UUID()
var name: String
init(name: String) {
self.name = name
}
}
The error says
Initializer 'init(_:)' requires that 'Binding<String>' conform to 'StringProtocol'
What this is saying is that the Text
initialiser wants something that conforms to StringProtocol
and Binding<String>
doesn't; food
is a Binding<String>
. You need to access the string that is bound, which you can do with the binding's wrappedValue
property -
ForEach($meal.foods) { food in
NavigationLink(destination: FoodView(food: food)) {
Text(food.name.wrappedValue)
}
}