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
}
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"
}
}
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)")
}
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)
}
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
}
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"
}
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")
}
}
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")
}
}
}
Top comments (0)