¿Qué es un Task?

Task representa la unidad mínima de código asíncrono.

Si tenemos una función síncrona, pero queremos ejecutar código asíncrono dentro de la misma, podemos usar Task. Por ejemplo:

func sync() {
executeProcess()
Task {
await callAsynchronous()
}
executeOtherProcess()
}

¿Cómo cancelar un Task?

Cuando creamos un Task podemos guardar una referencia a la misma en caso de que queramos poder cancelarla luego.

let task = Task {
await callAsynchronous()
}
task.cancel()

En este caso, guardamos una referencia al objeto en task y luego ejecutamos cancel().

Puedes utilizar la propiedad Task.isCancelled para saber si una tarea ya ha sido cancelada. De la misma forma puedes ejecutar Task.checkCancellation(), el cual devuelve un CancellationError si la tarea ya ha sido cancelada.

El siguiente código verifica si la tarea ha sido cancelada antes de ejecutarse:

func generate() -> Int async {
... // Código de procesamiento
if Task.isCancelled { return 0 }
... // Más código de procesamiento
}

Al verificar Task.isCancelled antes de ejecutar cualquier código que deba ser procesado, nos ahorramos el costo de ese procesamiento si la tarea ha sido cancelada, ya que no será necesario llevarlo a cabo.

Otra manera es usando withTaskCancellationHandler(operation:onCancel:). Este ejecuta una tarea, pero puedes pasar un bloque de código que se ejecutará cuando la tarea sea cancelada.

func start() async {
await withTaskCancellationHandler {
await generate()
} onCancel: {
debugPrint("Tarea cancelada")
}
}

En este caso si se cancela la tarea creada cuando ejecutamos generate(). Se ejecutará lo que pongamos en onCancel, en este caso imprimirá el mensaje Tarea cancelada en consola.

Establecer la prioridad de un Task

Si consultamos la documentación para Task, veremos que acepta los parámetros priority y operation: Task(priority:operation).

priority indica la prioridad del Task. Esto puede afectar el orden en que se ejecuta nuestro código con respecto a otras tareas asíncronas. Un Task por defecto hereda la prioridad del contexto donde se ejecuta.

Las diferentes prioridades por las que podemos optar son:

  • Background
  • High
  • Low
  • Medium
  • UserInitiated
  • Utility

Para indicar la prioridad solo necesitamos pasar el valor cuando instanciamos el objeto, ejemplo:

let task = Task(priority: .high) {
// ...
}

En este caso indicamos que la prioridad high. Es necesario saber que asignar una prioridad alta no quiere decir que nuestro código se ejecutará inmediatamente. El Executor decidirá el orden de ejecución, tomando en cuenta todas las tareas en cola.

Puedes consultar la prioridad de una tarea usando Task.currentPriority. Por defecto cuando creamos un Task este hereda la prioridad del contexto donde se crea. ¿Y qué si no queremos heredar la prioridad? Utilizamos tareas desacopladas.

Utilizando Tareas Desacopladas (Detached Task)

Si no quieres heredar el contexto donde ejecutas un Task, debes usar Task.detached(priority:operation). Este constructor es muy similar al que utilizamos con Task(priority:operation) anteriormente, solo que en este caso la tarea creada no hereda el contexto donde es creada.

Task.detached(priority: .background) {
// ...
}

Comparte este artículo

Subscríbete a nuestro Newsletter

Mantente al día en el mundo de las aplicaciones móviles con nuestro blog especializado.

Artículos semanales

Todas las semanas artículos nuevos sobre el mundo de las aplicaciones móviles.

No spam

No te enviaremos spam, solo contenido de calidad. Puedes darte de baja cuando quieras.

Contenido de calidad

Nada de contenido generado de manera automática usando ChatGPT.

Recomendaciones

Tips indispensables sobre mejores prácticas y metodologías.

© 2024 AsyncLearn