swiftstructswiftuiswift-structsswift-class

How to update the values of a struct in a View


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


Solution

  • 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")
                }
            }
        }
    }