The intent here is generate a new random number every time MyView loads while keeping that randomly generated number unaffected with any MyView refresh. However, none of the approaches below work. I will explain each approach and its outcome. Any ideas on how to properly accomplish what I am asking?
Approach #1: I assumed a new number is generated every time MyView loads. However, a random number is generated once for the entire app lifetime. I placed a button to force a view refresh, so when I press the button a new random number should not generate, which is what happens. What is wrong with this approach?
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: MyView()) {
Text("Link to MyView")
}
}
}
}
struct MyView: View {
@State var randomInt = Int.random(in: 1...100)
@State var myMessage: String = ""
var body: some View {
Text(String(randomInt))
Button("Press Me") {
myMessage = String(randomInt)
}
Text(myMessage)
}
}
Approach #2: I tried to update randomInt variable via let inside the Body but this generates a new random number every time the button is pressed (which is forcing a view refresh). Again, not the intended outcome. What is wrong with this approach?
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: MyView()) {
Text("Link to MyView")
}
}
}
}
struct MyView: View {
@State var randomInt = 0
@State var myMessage: String = ""
var body: some View {
let randomInt = Int.random(in: 1...100)
Text(String(randomInt))
Button("Press Me") {
myMessage = String(randomInt)
}
Text(myMessage)
}
}
Approach #3: The idea here to pass a new randomly generated integer every time the "Link to MyView" is pressed. I assumed that Int.Random is ran and passed every time Content View loads. However, a random number is only generated the first-time the entire app runs. What is wrong with this approach?
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
NavigationLink(destination: MyView(randomInt: Int.random(in: 1...100))) {
Text("Link to MyView")
}
}
}
}
struct MyView: View {
@State var randomInt = 0
@State var myMessage: String = ""
var body: some View {
Text(myMessage)
Button("Press Me") {
myMessage = String(randomInt)
}
}
}
2
Answers
Approach #1:
MyView
is created once, whenContentView
renders.Inside
MyView
,randomInt
is set when the view is first created and then never modified. When you press the button,myMessage
is set, butrandomInt
is never changed. If you wantedrandomInt
to change, you’d want to say something like:inside your button action:
Approach #2:
You’re creating a new
randomInt
variable in the local scope by declaringlet randomInt =
inside the view body.Instead, if I’m reading your initial question correctly, I think you’d want something using
onAppear
:You’ll see that with this, every time you go back in the navigation hierarchy and then revisit MyView, there’s a new value (since it appears again). The button triggering a re-render doesn’t re-trigger
onAppear
Approach #3:
MyView
gets created on the first render of the parent view (ContentView
). Unless something triggers a refresh ofContentView
, you wouldn’t generate a new random number here.In conclusion, I’m a little unclear on what the initial requirement is (what does it mean for a View to ‘load’? Does this just mean when it gets shown on the screen?), but hopefully this describes each scenario and maybe introduces the idea of
onAppear
, which seems like it might be what you’re looking for.Addendum: if you want the random number to be generated only when
ContentView
loads (as the title says), I’d create it inContentView
instead of yourMyView
and pass it as a parameter.I work on a way that always make a new random, your problem was you just used initialized State over and over! Without changing it.
Maybe the most important thing that you miss understood was using a State wrapper and expecting it performance as computed property, as you can see in your 3 example all has the same issue in different name or form! So for your information computed property are not supported in SwiftUI until Now! That means our code or us should make an update to State Wrappers, and accessing them like you tried has not meaning at all to them.