Search code examples
swiftswiftuiswift-concurrency

SWIFTUI: Invalid conversion from 'async' function of type '(IndexSet) async


I am learning SWIFTUI and trying to do some app to test my knowledge without actually following a tutorial, as I like to wrap my head around why things work certain way. It's how I learn :)

So, I am trying to call a function to post some data through an API. The method is inside of the ViewModel. The view is a List, and I need to be able to trigger .OnDelete modifier to trigger the API call through the viewmodel.

but I am always faced with the error:

Invalid conversion from 'async' function of type '(IndexSet) async -> Void' to synchronous function type '(IndexSet) -> Void'

here's the code.

in ContentView.swift:

        // there is a @State var res = PostsViewModel() above the body!
    List { 
        ForEach(res.posts, id:\.self){ item in
            VStack {
                Text(item.title) 
                    .font(.headline)
                Text("\(item.content) <> \(item._id)")
            }
            
        }
        .onDelete{ IndexSet in
                var index: Int = -1
                for idx in IndexSet {
                    index = idx
                }
                print("index ix \(index)")

                 await res.updateData(at: index)
                

        }

    }

In PostViewModel.swift:

    func updateData(at index: Int) async {
        let item = posts[index]
        print(item._id)
        guard let url = URL(string: "{URL HERE HIDDEN}/api/posts/\(item._id)") else {
            print("Error: cannot create URL")
            return
        }
        struct UploadData: Codable {
            let title: String
            let content: String
        }
        
        // Add data to the model
        let uploadDataModel = UploadData(title: "Hello", content: "World!!")
        
        // Convert model to JSON data
        guard let jsonData = try? JSONEncoder().encode(uploadDataModel) else {
            print("Error: Trying to convert model to JSON data")
            return
        }
        // Create the request
        var request = URLRequest(url: url)
        request.httpMethod = "PUT"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        do {
            guard let (data, _) = try? await URLSession.shared.upload(for: request, from: jsonData) else {
                 print("failed to connect")
                return
            }

            guard let decodedOrder = try JSONDecoder().decode(PostsModel?.self, from: data) else {
                 print("failed to decode")
                return
            }
                print(decodedOrder.content)
                
            } catch {
                print("Checkout failed.")
                return
            }
}

what am I doing wrong here?


Solution

  • Wrap the asynchronous function in a Task

    Task {
        await res.updateData(at: index)
    }
    

    And if PostsViewModel is a class declare a @StateObject

    @StateObject var res = PostsViewModel()