Async + await function and SwiftUI view

I have data that needs to be requested from backend and then presented as graph.
Im trying to use new async+await and wonder what is the best patter/practice would be.

var body: some View {
        VStack {
            
            ZStack {
                AreaGraphView( dataPoints: modelData.todayTimeline())
            }
    }
}

ModelData snippet

@Observable final class ModelData {

// ...

    func todayTimeline() async -> [DataPoint]  {
         // some async work
    }
 
    // ....
}

One of options I consider do call to modelData.todayTimeline() in onAppear. It would mean I need to pass dummy or empty data to AreaGraphView.
Any other options?

There is a task modifier that allows you to call an async task. It will be bound to the view's lifetime and cancelled if the view gets discarded.

PS.: Unfortunately this isn't the right platform to ask SwiftUI questions.

Maybe something like so:

enum LoadingState<T> {
  case loading
  case failed(Error)
  case loaded(T)
}

struct LoadingView<Value, Content: View>: View {
   let operation: () async throws → Void
   @ViewBuilder var content: (Value) -> Content

   @State private var loadingState = LoadingState<Value>.loading
   
   var body: some View {
      Group {
         switch loadingState {
         case .loading:
           ProgressView()
         case .failed(let error):
           Text("Failed with error: \(error)")
         case .loaded(let value):
           content(value)
         }
      }.task {
         do {
           loadingState = .loading
           let result = try await operation()
           loadingState = .loaded(result)
         } catch {
           loadingState = .failed(error)
         }
      }
    }
}

And then your view could be wrapped like so:

var body: some View {
  LoadingView(operation: model.todayTimeline) { timeline in
    AreaGraphView(dataPoints: timeline)
  }
}
2 Likes

Thank you!