6

@State variable initialization in SwiftUI

 1 year ago
source link: https://sarunw.com/posts/state-variable-initialization/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

@State variable initialization in SwiftUI


Table of Contents

There might be a time when you want to initialize the value of a @State variable in an initializer.

struct CounterView: View {
@State private var count: Int

init(count: Int) {
self.count = count
}
...
}

Since Xcode 14, you can easily do this.

The bigger question is not how we can do it. But should we do it?

Let's learn how to do it and then judge for yourselves whether you want to do it or not.

You can easily support sarunw.com by checking out this sponsor.

Ship your iOS apps faster!

Sponsor sarunw.com and reach thousands of iOS developers.

How to initialize @State variable in an initializer

Here is an example of CounterView, which has its own count state property.

struct CounterView: View {
@State private var count = 0

var body: some View {
VStack {
Text("Counter: \(count)")
Button("+1") {
count += 1
}
}
}
}

We can use it like this.

struct ContentView: View {
var body: some View {
CounterView()
.font(.title)
}
}
A view with a state variable.

A view with a state variable.

If we want other views to set the initial count value of the CounterView, we need to create an initializer that sets the count property.

Since Xcode 14, we can do it just like a normal variable.

struct CounterView: View {
@State private var count: Int

init(count: Int) {
self.count = count
}

var body: some View {
VStack {
Text("Counter: \(count)")
Button("+1") {
count += 1
}
}
}
}

In the past, initializing a @State variable like this wasn't possible. You have to initialize it in the property wrapper way like this _count = State(initialValue: count).

You might encounter a solution like this on the internet, but we no longer need this since the compiler is smarter now (Xcode 14).

struct CounterView: View {
@State private var count: Int

init(count: Int) {
_count = State(initialValue: count)
}

var body: some View {
VStack {
Text("Counter: \(count)")
Button("+1") {
count += 1
}
}
}
}

Then we can use it like this.

struct ContentView: View {
var body: some View {
CounterView(count: 5)
.font(.title)
}
}

We initialize CounterView(count: 5) with count variable set to five. When we run the app, this is what we got.

A CounterView initial count is five.

A CounterView initial count is five.

Should we initialize @State variable in an initializer

As you can see, our previous example works very well. We can control the @State variable from the call site.

But there is a behavior that you should be aware of.

Setting a @State variable like this will only work for the very First time. After the @State variable is create and initialize, SwiftUI will make sure it persisted through the lifetime of the view.

That means the subsequence change of count value from the initializer won't take any effect.

It might be easier to understand this with an example.

In this example, instead of hard-coded count value to five, CounterView(count: 5), we make it changeable using @State private var externalCount = 2.

struct ContentView: View {
// 1
@State private var externalCount = 2

var body: some View {
VStack {
// 2
CounterView(count: externalCount)

Text("External Count: \(externalCount)")
Button("External +1") {
// 3
externalCount += 1
}
}
.font(.title)
}
}

1 We create @State variable to represent an initial value for our CounterView.
2 We use the @State variable, externalCount, to initalize CounterView.
3 We create a button to increase value of externalCount.

On the first launch, CounterView was initialized with externalCount, which had an initial value of two.

And that's it, CounterView.count is created and persisted.

Even if we change the value of externalCount later, it no longer affects the value of the CounterView.

The change in the externalCount value has no affects on the CounterView.

The change in the externalCount value has no affects on the CounterView.

You can easily support sarunw.com by checking out this sponsor.

Ship your iOS apps faster!

Sponsor sarunw.com and reach thousands of iOS developers.

Conclusion

A @State variable means to use internally within a view. Apple suggested we always declare state variables as private.

As you can see, Apple suggested that with a good reason. Exposing a state variable as we did might cause confusing to a newcomer or even your future self since the state variable can only initialize once.

If you need to initialize a state property like this, it might be a good time to reorganize your view. Maybe some data is sitting in the wrong places.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK