Home > Net >  Task{} works but .task{} throws Invalid conversion from throwing function of type error?
Task{} works but .task{} throws Invalid conversion from throwing function of type error?

Time:01-25

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
  • Related