Reputation: 5220
I am building a custom View struct with a large and complicated model that I want to update from within the var body : some View { ... }
property (ex. tapping on a button representing a table column in the view should change the sort order of the rows in the table). I am not allowed to modify this model from within body
because self
is immutable however:
struct MyTable : View {
struct Configuration {
// a LOT of data here, ie header, rows, footer, style, etc
mutating func update() { ... } // this method must be called before view render
}
var configuration : Configuration
var body : some View {
// build the view here based on configuration
self.configuration.columns[3].sortAscending = false // error, `self` is immutable
self.configuration.update() // error, `self` is immutable
}
}
I really don't want to create @State variables for all of the configuration data because 1) there's a lot of configuration data, 2) it would be difficult to model the model in such a way.
I tried instead making configuration
a @State var, but I am unable to set the configuration object at init()
time even though the code compiles and runs! (BTW, the configuration
var now needs to be initialized before init, otherwise I get an error on the line self.configuration = c
that self
is used before all members are initialized -- this is likely a complication with using @State which is a property wrapper.)
struct MyTable : View {
struct Configuration {
...
}
@State var configuration : Configuration = Configuration() // must initialize the @State var
init(configuration c: Configuration) {
self.configuration = c // does not assign `c` to `configuration` !!!
self.$configuration.wrappedValue = c // this also does not assign !!!
self.configuration.update()
}
var body : some View {
// build the view here based on configuration
self.configuration.columns[3].sortAscending = false // ok, no error now about mutating a @State var
self.configuration.update() // ok, no error
}
}
Upvotes: 0
Views: 39
Reputation: 5220
I came up with a work around where I don't need to call update()
in MyTable.init()
by creating a custom init()
in Configuration
that will call update()
. This way the init()
in MyTable
is unnecessary and this approach resolves all previously encountered problems:
struct MyTable : View {
struct Configuration {
...
init(...) {
...
self.update()
}
mutating func update() { ... } // this method must be called before view render
}
@State var configuration : Configuration // note that this property can't be marked private because we want to inject `configuration` at init
var body : some View {
// build the view here based on configuration
self.configuration.columns[3].sortAscending = false // ok, no error now about mutating a @State var
self.configuration.update() // ok, no error
...
}
}
Then in my calling code:
return MyTable.init(configuration: MyTable.Configuration.init(...))
Upvotes: 0