I would like to initialise the value of a @State
var in SwiftUI through the init()
method of a Struct
, so it can take the proper text from a prepared dictionary for manipulation purposes in a TextField.
The source code looks like this:
struct StateFromOutside: View {
let list = [
"a": "Letter A",
"b": "Letter B",
// ...
]
@State var fullText: String = ""
init(letter: String) {
self.fullText = list[letter]!
}
var body: some View {
TextField($fullText)
}
}
Unfortunately the execution fails with the error Thread 1: Fatal error: Accessing State<String> outside View.body
How can I resolve the situation? Thank you very much in advance!
SwiftUI doesn't allow you to change @State
in the initializer but you can initialize it.
Remove the default value and use _fullText
to set @State
directly instead of going through the property wrapper accessor.
@State var fullText: String // No default value of ""
init(letter: String) {
_fullText = State(initialValue: list[letter]!)
}
I would try to initialise it in onAppear
.
struct StateFromOutside: View {
let list = [
"a": "Letter A",
"b": "Letter B",
// ...
]
@State var fullText: String = ""
var body: some View {
TextField($fullText)
.onAppear {
self.fullText = list[letter]!
}
}
}
Or, even better, use a model object (a BindableObject
linked to your view) and do all the initialisation and business logic there. Your view will update to reflect the changes automatically.
Update: BindableObject
is now called ObservableObject
.
The top answer is incorrect. One should never use State(initialValue:)
or State(wrappedValue:)
to initialize state in a View
's init
. In fact, State
should only be initialized inline, like so:
@State private var fullText: String = "The value"
If that's not feasible, use @Binding
, @ObservedObject
, a combination between @Binding
and @State
or even a custom DynamicProperty
In your specific case, @Bindable
+ @State
+ onAppear
+ onChange
should do the trick.
More about this and in general how DynamicProperty
s work, here.
Depending on the case, you can initialize the State in different ways:
// With default value
@State var fullText: String = "XXX"
// Not optional value and without default value
@State var fullText: String
init(x: String) {
fullText = x
}
// Optional value and without default value
@State var fullText: String
init(x: String) {
_fullText = State(initialValue: x)
}
It's not an issue nowadays to set a default value of the @State
variables inside the init
method. But you MUST just get rid of the default value which you gave to the state and it will work as desired:
,,,
@State var fullText: String // <- No default value here
init(letter: String) {
self.fullText = list[letter]!
}
var body: some View {
TextField("", text: $fullText)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With