0

I ran in to some problems and wrote some basic variant to show the problem:

import SwiftUI

struct PersonStruct {
    // Requires @State because self.name is immutable otherwise
    @State var name:String

    init (_ name: String) { self.name = name }
    
    func changeName(_ name: String) {
        self.name = name
        print (self.name)
    }
}

class PersonClass {
    var name:String

    init (_ name: String) { self.name = name }
    
    func changeName(_ name: String) {
        self.name = name
        print (self.name)
    }
}

struct ContentView: View {
    var person1:PersonStruct = PersonStruct("Peter S.")
    var person2:PersonClass = PersonClass("Peter C.")

    var body: some View {
        VStack {
            Text(person1.name)
            .padding()
            Text(person2.name)
            .padding()
            
            Button("Change name") {
                person1.changeName("Trevor")
                person1.name = "Trevor"

                person2.changeName("Trevor")
                person2.name = "Trevor"

                print("---")
                print (person1.name)
                print (person2.name)
            }
            .padding()
        }
        .font(.title)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

The person variables behave different, pressing the button changes the name of person2 from "Peter C" to Trever - as seen by "print" in the console. But the name of person1 will not be changed, it stays at "Peter S." ...

So, the struct does not seem to work at all.

And in both cases, the Text outputs in the View will both not change - "Peter C" and "Peter S" stay visible.

Why does the content from person1 not change? I even used both the function "changeName()" and also tried to set the name directly. To no avail :-(

2
  • 1
    You should not use @State in a non SwiftUI struct, I.e one that doesn’t conform to View. You should on the other hand use @State for both your properties in ContentView. Fix that and come back if you still have an issue Commented Aug 14, 2021 at 18:53
  • Removing the @State in the struct gave "Cannot assign to property: 'self' is immutable" as mentioned above. But the "mutating" from vadian did solve this! Commented Aug 14, 2021 at 19:04

1 Answer 1

2

First of all it's not required that name in the struct is marked with @State, actually it's wrong anyway, just make the function mutating

struct PersonStruct {
    var name : String

    init (_ name: String) { self.name = name }
    
    mutating func changeName(_ name: String) {
        self.name = name
        print (self.name)
    }
}

To be able to observe the class adopt ObservableObject and add the property wrapper @Published

class PersonClass : ObservableObject {
    @Published var name:String

    init (_ name: String) { self.name = name }
    
    func changeName(_ name: String) {
        self.name = name
        print (self.name)
    }
}

In the view declare the struct as @State and the class as @StateObject

@State private var person1 = PersonStruct("Peter S.")
@StateObject private var person2 = PersonClass("Peter C.")
Sign up to request clarification or add additional context in comments.

2 Comments

That worked like a charm, many thanks! Using "@State" instead of "@StateObject" seems to work too for person2 ...
The rules are: @State for value types and @StateObject for reference types.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.