blksld
blksld

Reputation: 129

Swift(UI) Error: Cannot use mutating member on immutable value: 'self' is immutable

Basically what i want to do is if you press the Button then entries should get a new CEntry. It would be nice if someone could help me out. Thanks!

struct AView: View {

   var entries = [CEntries]()

   var body: some View {
       ZStack {
           VStack {
               Text("Hello")
               ScrollView{
                   ForEach(entries) { entry in
                       VStack{
                        Text(entry.string1)
                        Text(entry.string2)
                    }
                }
            }
        }
        Button(action: {
            self.entries.append(CEntries(string1: "he", string2: "lp")) <-- Error
        }) {
            someButtonStyle()
        }
    }
}

}


The Class CEntries

 class CEntries: ObservableObject, Identifiable{
    @Published var string1 = ""
    @Published var string2 = ""

    init(string1: String, string2: String) {
        self.string1 = string1
        self.string2 = string2
    }
}

Upvotes: 3

Views: 6065

Answers (1)

New Dev
New Dev

Reputation: 49590

Views are immutable in SwiftUI. You can only mutate their state, which is done by changing the properties that have a @State property wrapper:

@State var entries: [CEntries] = []

However, while you could do that, in your case CEntries is a class - i.e. a reference type - so while you could detect changes in the array of entries - additions and removals of elements, you won't be able to detect changes in the elements themselves, for example when .string1 property is updated.

And it doesn't help that it's an ObservableObject.

Instead, change CEntries to be a struct - a value type, so that if it changes, the value itself will change:

struct CEntries: Identifiable {
    var id: UUID = .init()
    var string1 = ""
    var string2 = ""
}

struct AView: View {

   @State var entries = [CEntries]() 

   var body: some View {
       VStack() {
          ForEach(entries) { entry in
             VStack {
                Text(entry.string1)
                Text(entry.string2)
             }
          }
          Button(action: {
            self.entries.append(CEntries(string1: "he", string2: "lp"))
          }) {
              someButtonStyle()
          }
      }
   }
}

Upvotes: 9

Related Questions