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?
CodePudding user response:
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()