DEV Community

GoyesDev
GoyesDev

Posted on • Edited on

[SC] Manejo de errores en Task

Task<Success, Failure> es una estructura genérica que espera recibir el tipo de dato que devuelve y el tipo de error que arroja. No es necesario especificar estos valores cuando se implementa un Task, puesto que son inferidos automáticamente.

let tarea1: Task<Int, Swift.Error> = Task { () -> Int in
  throw URLError(.badURL)
}
let tarea2: Task<Int, Never> = Task { () -> Int in
  0
}
Enter fullscreen mode Exit fullscreen mode

Manejando errores dentro de un Task

Se puede manejar un error internamente, usando un do/catch.

let tarea: Task<String, Never> = Task { () -> String in
  do {
    throw URLError(.badURL)
  } catch {
    return "Hubo un error"
  }
}
Enter fullscreen mode Exit fullscreen mode

Esperar una tarea y atrapar potenciales errores

Si se quiere esperar a una tarea y atrapar un posible error, se puede usar la propiedad var value: Success { get async throws }.

En el siguiente ejemplo se espera por el resultado de la tarea tarea y se atrapa cualquier error en el bloque catch.

let tarea: Task<String, Error> = Task { () -> String in
  throw URLError(.badURL)
}
do {
  let result = try await self.tarea.value
} catch {
  print("Hubo un error: \(error)")
}
Enter fullscreen mode Exit fullscreen mode

Errores tipados y Tasks

Actualmente las tareas no tienen errores tipados. Es decir, el siguiente código producirá un error:

let throwingTask: Task<String, URLError> = Task { () -> String in
  throw URLError(.badURL)
}
Enter fullscreen mode Exit fullscreen mode

Manejo de errores completo dentro de un Task

Aunque Task no sea tipado (i.e. es de tipo Task<ResultType, any Error> o Task<ResultType, Never>), esto no necesariamente significa que al invocar a un método asíncrono se tenga que dar manejo a todos los casos de error.

Por ejemplo, considerar el siguiente tipo de error:

enum Error: Swift.Error {
  case dummyError, otroError
}
Enter fullscreen mode Exit fullscreen mode

Y el siguiente método asíncrono:

func asyncMethod(input: String) async throws -> String {
  try? await Task.sleep(for: .seconds(3))

  if input == "error" {
    throw Error.dummyError
  }

  return "result"
}
Enter fullscreen mode Exit fullscreen mode

Se puede invocar asyncMethod desde un Task, sin dar manejo a todos los errores:

Task(priority: .background) {
  do {
    let result = try await asyncMethod(input: "error")
    print(result)
// ⚠️ Notar que solo se atrapa Error.dummyError. No se atrapa `otroError` ni cualquier otro error
  } catch Error.dummyError {
    print("Hubo un error")
  }
}
Enter fullscreen mode Exit fullscreen mode

Esto trae implícito que el bloque que ejecuta esta tarea debe manejar el error, porque la tarea definida en realidad será de tipo Task<Void, any Error> como se puede comprobar a continuación:

.onAppear {
  Task<Void, any Swift.Error>(priority: .background) {
    do {
      let result = try await asyncMethod(input: "error")
      print(result)
    } catch Error.dummyError {
      print("Hubo un error")
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Bibliografía

Top comments (0)