How to update the values of a struct in a View

6.1k Views Asked by At

In SwiftUI I have a struct that want to hold data of the View. Let's say there is a View that user can create a recipe in it. It has a text field to type the recipe name, and options to choose and add to the array in the struct's properties.

I managed to make the struct and introduce it in the View but I cannot change it values. The values of the struct should be updated based on what users does on the View and the info they add to it. I made a simple View that whatever is entered in the TextField will be added in one of the properties of the struct. For the below code I get Cannot assign to property: 'self' is immutable

struct Recipe: Codable {
let user: Int
var recipeName, createdDate: String
let ingredients: [Ingredient]
let equipment: [[Int]]

enum CodingKeys: String, CodingKey {
    case user = "User"
    case recipeName = "RecipeName"
    case createdDate
    case ingredients = "Ingredients"
    case equipment = "Equipment"
 }
}

struct Ingredient: Codable {
   let ingredient, size: Int
}

VIEW:

struct ContentView: View {
    var recipe = Recipe(user: 1231, recipeName: "Recipe Name", createdDate: "SomeDate", ingredients: [Ingredient(ingredient: 1, size: 2)], equipment: [[1],[4],[5]])


    var body: some View {
        VStack {
            Text(self.recipe.recipeName)
            Button(action: {
                recipe.recipeName = "New Name" //Cannot assign to property: 'self' is immutable
            }) {
                Text("Change Name")
            }
        }
    }
}

Any idea how to solve this so I can interact with the struct and update its properties. I will use this struct variable in other Views as well.

Thanks in advance

2

There are 2 best solutions below

2
On BEST ANSWER

For the use-case as provided the most appropriate is to use view model as in example below

class RecipeViewModel: ObservableObject {
   @Published var recipe: Recipe
   init(_ recipe: Recipe) {
     self.recipe = recipe
   }
}

so in the view

struct ContentView: View {
    @ObservedObject var recipeVM = RecipeViewModel(Recipe(user: 1231, recipeName: "Recipe Name", createdDate: "SomeDate", ingredients: [Ingredient(ingredient: 1, size: 2)], equipment: [[1],[4],[5]]))


    var body: some View {
        VStack {
            Text(self.recipeVM.recipe.recipeName)
            Button(action: {
                self.recipeVM.recipe.recipeName = "New Name"
            }) {
                Text("Change Name")
            }
        }
    }
}
0
On

Add @State

@State var recipe = Recipe(..

Also, don't forget to add self. before using recipe inside button action.