I'm trying to show progress of a lengthy operation in a Text view. Using StateObject/Published var, I was hoping to see the Text change when the published var changes, however, I only see the last text appearing in the Text field. How can I dynamically change/update the Text field?
@StateObject var tt = TestText()
var body: some View {
Text(tt.text)
.padding()
.onAppear(perform: { tt.ChangeText() })
}
class TestText: ObservableObject {
@Published var text = "text 0"
func ChangeText() -> Void {
sleep(3) // some time-consuming stuff here
text = "text 1"
sleep(3) // id
text = "text 2"
sleep(3) // id
text = "text 3"
sleep(3) // id
text = "text 4"
sleep(3) // id
text = "text 5"
}
}
CodePudding user response:
your sleep(3)
is wrong, it does not simulate a long time consuming task,
it stops everything (including the UI update) for 3 seconds.
What you want is something like this to simulate a long time consuming task:
struct ContentView: View {
@StateObject var tt = TestText()
var body: some View {
Text(tt.text)
.padding()
.onAppear(perform: { tt.ChangeText() })
}
}
class TestText: ObservableObject {
@Published var text = "text 0"
func ChangeText() -> Void {
DispatchQueue.main.asyncAfter(deadline: .now() 2) {
self.text = "text 1"
}
DispatchQueue.main.asyncAfter(deadline: .now() 4) {
self.text = "text 2"
}
DispatchQueue.main.asyncAfter(deadline: .now() 6) {
self.text = "text 3"
}
DispatchQueue.main.asyncAfter(deadline: .now() 8) {
self.text = "text 4"
}
DispatchQueue.main.asyncAfter(deadline: .now() 10) {
self.text = "text 5"
}
}
}
CodePudding user response:
Thanks for pointing me in the right direction. The sleep was just a placeholder for a lengthy operation, but the various operations run sequentially. With some slight modification to your code I achieve my intended goal. Now the code-bits run one after the other, showing the updated text after each step.
import Foundation
class TestText: ObservableObject {
@Published var text = "text 0"
func ChangeText() -> Void {
DispatchQueue.main.asyncAfter(deadline: .now() 2) {
self.DoSomething()
self.text = "text 1"
DispatchQueue.main.asyncAfter(deadline: .now() 0.1) {
self.DoSomething()
self.text = "text 2"
DispatchQueue.main.asyncAfter(deadline: .now() 0.1) {
self.DoSomething()
self.text = "text 3"
DispatchQueue.main.asyncAfter(deadline: .now() 0.1) {
self.DoSomething()
self.text = "text 4"
DispatchQueue.main.asyncAfter(deadline: .now() 0.1) {
self.DoSomething()
self.text = "text 5"
}
}
}
}
}
}
func DoSomething() -> Void {
sleep(3) // these are in fact various bits of codes, which have to run in sequence one after the other, DoSomething is just a placeholder for the moment
}
}