For some reason, the .task
is not invoking my function automatically when the view gets open. If I call the function using Button("click") { Task { ... } }
, then it works.
Why does the .task
not work here?
import SwiftUI
struct BookTextView: View {
@StateObject var viewModel: BookTextViewModel = BookTextViewModel()
var body: some View {
Text("HELLO!")
Group {
switch viewModel.result {
case .empty:
EmptyView()
case .loading:
ProgressView()
case .failure(let error):
Text(error.localizedDescription)
// ErrorView(error: error, retryHandler: viewModel.load)
case .success(let bookText):
ScrollView {
VStack(spacing: 20) {
Text(bookText.text)
}
.padding()
}
}
}.task {
do {
try await viewModel.load()
} catch {
}
}
}
}
My model
import SwiftUI
@MainActor class BookTextViewModel: ObservableObject {
enum AsyncResult<Success> {
case empty
case loading
case success(Success)
case failure(Error)
}
@Published var bookText: BookText?
@Published var result: AsyncResult<BookText> = .empty
func load() async {
print("loading?")
...
This is how i call the view from another component
detail: {
BookTextView()
.task
runs when the UI objects being described by the View
model data structs appear on screen. EmptyView()
describes a nothing UI, hence no UI object ever appears. So, try removing that and move your Text("HELLO!")
into the .empty
case and it should fix it.
.task
will also run when it re-appears (e.g. going back) so you might want to check the model data is not already loaded so save needlessly loading it again. You could also position the .task
strategically so it only runs in the situation there is no data, e.g. on a placeholder Text("Loading...")
inside an if
that checks if an optional state is nil.
Some tips to improve your code: put the text into a result enum instead of a separate var. Remove the object and just use @State var result
because .task
sort of already makes an object behind the scenes to manage the lifecycle. Declare your async fun somewhere else that is more easily testable by making it return something or throw.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With