Search code examples
swiftasync-awaitswiftuiios15swift5

Can I use Swift async/await to call void methods in succession?


In a ViewModel, I'm currently using callbacks to 1. make an API call and set data1, 2. use data1 in a second API call to set data2, then use data2 in a third function to parse and set a published value to be used in a View.

The examples I've seen so far have been based on awaiting return values. I only want to run void functions in succession. I've tried implementing the concept below but I keep getting "async in a function that does not support concurrency".

// ViewModel

var data1:Data?
var data2:Data?
@Published var myString:String?

func getFirstData() async -> Void {
  data1 = someAPIrequest()
}

func getSecondData() async -> Void {
  data2 = anotherAPIrequest(await data1)
}

func setViewString() {
  myString = data2!.name
}

// View

var body: some View {
  Text(await model.myString)
}.onAppear{
  getFirstData()
  getSecondData()
}

Solution

  • you could try something like this:

    import SwiftUI
    
    @main
    struct TestApp: App {
        var body: some Scene {
            WindowGroup {
                ContentView()
            }
        }
    }
    
    struct ContentView: View {
        @StateObject var model = MyDataModel()
        
        var body: some View {
            Text(model.myString ?? "")
                .task {
                    await model.getFirstData()
                    await model.getSecondData() // will wait for getFirstData to finish
                    model.setViewString() // will wait for getSecondData to finish
                }
        }
    }
    
    class MyDataModel: ObservableObject {
        var data1: Data?
        var data2: Data?
        
        @Published var myString: String?
        
        func getFirstData() async -> Void {
            // just for testing
            self.data1 = "data1-data1-data1".data(using: .utf8)  // someAPIrequest()
        }
        
        func getSecondData() async -> Void {
            // just for testing
            data2 = data1  // anotherAPIrequest(data1)
        }
        
        func setViewString() {
            // just for testing
            myString = String(data: data2!, encoding: .utf8)
        }
    }