I am trying to understand the reason behind why does Task{}
works but when I do it with the VStack{}.task{}
I am getting the error:
Invalid conversion from throwing function of type '@Sendable () async throws -> ()' to non-throwing function type '@Sendable () async -> Void'
I am trying to have the fetchWeather()
function run the moment the view starts without having the user to tap on the button. (If the below way is the correct way to do so) but ran upon this error and am really curious to the reasoning behind this error
Below is my code:
struct WeatherView: View {
var body: some View {
VStack{
Text("Hello, World!")
Button("Get Weather", action: {
// Works when I tap the button
// Task {
// try await fetchWeather()
// }
})
}
//*******Xcode error with invalid conversion*******
.task {
try await fetchWeather()
}
}
}
struct WeatherView_Previews: PreviewProvider {
static var previews: some View {
WeatherView( )
}
}
The function:
func fetchWeather () async throws {
let URLString = "https://api.openweathermap.org/data/2.5/weather?appid=someAPIKeyshere&q=seattle"
let (data, response) = try await URLSession.shared.data(from: URL(string: URLString)!)
guard let httpResponse = response as? HTTPURLResponse,
httpResponse.statusCode == 200 else {
throw ResponseError.someError
}
let decodedResponse = try? JSONDecoder().decode(WeatherData.self, from: data)
print("This is in decodedResponse: \(decodedResponse)")
}
thanks in advance!
CodePudding user response:
That´s a known behaviour of Task{}
. It hides errors in its result and can have unhandeled throwing
functions. The .task
modifier does not. If you want to use throwing
functions inside it you need to handle them with a do/catch
block.
.task {
do{
try await fetchWeather()
} catch{
}
}
You can read on swift forum about that issue.
CodePudding user response:
Look at the error message you're getting…
Your function is of type:
@Sendable () async throws -> ()
whereas the .task
modifier is expecting…
@Sendable () async -> Void
The difference is the throws
.
You resolve this, you need to handle errors thrown by your function, e.g.…
.task {
do {
try await fetchWeather()
} catch {
// handle error
}
}
You can compare the parameters that the initialiser for Task
and the .task
modifier take:
Task.init
init(priority: TaskPriority? = nil, operation: @escaping @Sendable () async throws -> Success)
.task
modifier
func task(priority: TaskPriority = .userInitiated, _ action: @escaping @Sendable () async -> Void) -> some View