Reputation: 5599
I am creating a SwiftUI view where I have three possible conditions, and want to show different content based on which condition is met. A simplified example:
struct ContentView: View {
@State var condition1 = true
@State var condition2 = false
var body: some View {
VStack {
if condition1 {
Text("text1")
} else if condition2 {
Text("text2")
} else {
Text("text3")
}
}.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.condition2 = true
}
DispatchQueue.main.asyncAfter(deadline: .now() + 4.0) {
self.condition1 = false
}
DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) {
self.condition2 = false
}
}
}
}
What I expect to happen:
1) The UI shows text1
when the app starts
2) The UI still shows text1
after 2 seconds (both variables are true
)
3) The UI shows text2
after 4 seconds (condition2
is true
but condition1
is now false
)
4) The UI shows text3
after 6 seconds (both variables are now false
)
What actually happens:
1) The UI shows text1
when the app starts
2) The UI shows text1
after 2 seconds
3) The UI shows text2
after 4 seconds
4) The UI continues to show text2
after 6 seconds
Weirdly enough, if I put breakpoints in the UI code, the line showing text3 is executed, it just seems the UI never updates. Even more weirdly, if I put a Spacer().frame(width: 0, height: 0)
in that else case, everything works as expected.
Is this a bug in SwiftUI or what's going on here?
Upvotes: 1
Views: 1603
Reputation: 257729
Well, actually if to add buttons and switch states on buttons then all works, so this is something with delayed updates (maybe racing, maybe bug... did not dig further)
Here is actually solution, which works (tested with Xcode 11.2 /iOS 13.2) ... separate those conditional dependent views into dedicated view builder, like below
struct TestRefreshOnCondition: View {
@State var condition1 = true
@State var condition2 = false
var ConditionalView: some View {
Group {
if condition1 {
Text("text1")
} else if condition2 {
Text("text2")
} else {
Text("text3")
}
}
}
var body: some View {
VStack {
ConditionalView
}.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.condition2 = true
}
DispatchQueue.main.asyncAfter(deadline: .now() + 4.0) {
self.condition1 = false
}
DispatchQueue.main.asyncAfter(deadline: .now() + 6.0) {
self.condition2 = false
}
}
}
}
Upvotes: 2