Should we manually call @StateObject initializer
Table of Contents
In the previous article, How to initialize @StateObject with parameters in SwiftUI, I share how to initialize @StateObject with parameters by using a default value and onAppear
modifier.
But there is another controversial way to initialize @StateObject
, that is, initialize it in an initializer using the StateObject(wrappedValue:)
.
This article will discuss whether we should use this format or not.
Here is what the solution looks like.
class DashboardViewModel: ObservableObject {
@Published var greeting: String
init(name: String) {
greeting = "Hello, \(name)!"
}
}
struct DashboardView: View {
@StateObject private var viewModel: DashboardViewModel
init(name: String) {
_viewModel = StateObject(wrappedValue: DashboardViewModel(name: name))
}
var body: some View {
Text("Greeting: \(viewModel.greeting)")
}
}
What is the problem with StateObject(wrappedValue:)
The reason that I didn't include this method in the previous post is because of this statement in the Apple documentation of StateObject
.
You don't call this initializer directly. Instead, declare a property with the
@StateObject
attribute in a View, App, or Scene, and provide an initial value:
struct MyView: View {
@StateObject var model = DataModel()
// ...
}
You can easily support sarunw.com by checking out this sponsor.
Localization Buddy: Easiest way to localize and update App Store metadata.
Should we initialize @StateObject in Initializer
Even though Apple said not to use it, I know many people use StateObject(wrappedValue:)
to initialize @StateObject
variable. I also use it sometimes, but what is written in the documentation keeps bugging me.
Finally, I found the answer that ends my suffering.
I found the tweet from Asperi. He posted this screenshot from the Ask Apple event.
In the screenshot, an Apple Engineer state that it is OK to manually initialize a @StateObject
variable in an init function.
@StateObject var store: Store
init(id: UUID) {
self._store = StateObject(wrappedValue: Store(id: id))
}
When he got asked about the StateObject
documentation, he mentioned that the documentation tries to be more conservative since it might cause confusion and issue to the one that does not get used to the platform.
The above conversation can confirm that it is OK to initialize @StateObject
manually, but what about the issue that this can cause?
You can easily support sarunw.com by checking out this sponsor.
Localization Buddy: Easiest way to localize and update App Store metadata.
What you should be aware of when manually initializing @StateObject
The only thing that you should be aware of when manually initializing @StateObject
is it will initialize once at the beginning of the view lifetime.
The subsequent change of the initialize value wouldn't affect @StateObject
.
To get a better understanding of the problem, let's see an example.
We got the DashboardView
with a @StateObject
.
class DashboardViewModel: ObservableObject {
@Published var greeting: String
init(name: String) {
greeting = "Hello, \(name)!"
}
}
struct DashboardView: View {
@StateObject private var viewModel: DashboardViewModel
// 1
init(name: String) {
_viewModel = StateObject(wrappedValue: DashboardViewModel(name: name))
}
var body: some View {
Text("Greeting: \(viewModel.greeting)")
}
}
1 DashboardView
accept the name
parameter which use to initialize DashboardViewModel
.
We use DashboardView
and initialize it with the "Sarunw 2" string, "Sarunw (count)" with the count
equals 2
.
struct ContentView: View {
// 1
@State var count = 2
var body: some View {
VStack {
// 2
DashboardView(name: "Sarunw \(count)")
Text("Count: \(count)")
Button("+1") {
// 3
count += 1
}
}
}
}
1 The initial value of count
is 2
.
2 Initialize DashboardView
with "Sarunw (count)".
3 We have a button that count
value.
DashboardView
capture the value of count
when it was first created. So the name
is "Sarunw 2".
If you later increase the count
value, DashboardView
wouldn't notice that change.
The StateObject
will initialize only once for the lifetime of the DashboardView
.
As you can see, DashboardViewModel
take the count
value of 2 at the start and no longer change through its lifecycle, even when the count
change.
Read more article about SwiftUI, Data, Property Wrapper, or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet Share@State variable initialization in SwiftUI
Learn how to initialize a state variable and discuss whether you should do it or not.
What is the difference between List and ForEach in SwiftUI
Even though ForEach and List have similar syntax, they serve different purposes. Let's learn about their differences.