Programação Assíncrona em Swift: Guia Completo na Prática
Programação assíncrona é um dos conceitos-chave do desenvolvimento moderno para iOS e macOS. Em Swift, a partir da versão 5.5, surgiu um poderoso sistema de Structured Concurrency, que tornou o trabalho com assincronia simples e seguro. Neste artigo, vamos explorar as principais ferramentas: async/await, Task, Actor e Sendable, além de mostrar suas aplicações em exemplos reais.
1. Fundamentos de async/await: como parar de escrever closures e começar a viver
Antes do async/await, o código assíncrono em Swift era escrito com closures e delegates, o que frequentemente levava ao "inferno dos callbacks". A abordagem moderna permite escrever código assíncrono de forma tão linear quanto o síncrono.
Declarar uma função assíncrona é feito com a palavra-chave async. Chamar essa função requer um contexto que suporte assincronia e a palavra-chave await.
// Exemplo de função assíncrona para carregar dadosfunc fetchUserData(userID: String) async throws -> User { let url = URL(string: "https://api.example.com/users/\\(userID)")! let (data, response) = try await URLSession.shared.data(from: url) guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else { throw URLError(.badServerResponse) } let user = try JSONDecoder().decode(User.self, from: data) return user}
// UsoTask { do { let user = try await fetchUserData(userID: "123") print("Nome do usuário: \\(user.name)") } catch { print("Erro: \\(error)") }}Características principais:
async— marcador de função assíncronaawait— ponto de suspensão da execução- A função pode ser tanto
asyncquantothrowssimultaneamente - A thread não é bloqueada — durante a espera, ela pode executar outro trabalho
2. Task e TaskGroup: gerenciamento de tarefas paralelas
Task é a unidade básica de trabalho assíncrono. Ela cria uma nova tarefa assíncrona que é executada no pool global de threads. TaskGroup permite executar várias tarefas em paralelo e coletar seus resultados.
Criação e cancelamento de Task
// Criando uma tarefalet task = Task { let result = await performLongOperation() return result}
// Obtendo o resultadolet value = await task.value
// Cancelando a tarefatask.cancel()
// Verificando cancelamento dentro da tarefafunc performLongOperation() async -> String { // Verifica se a tarefa foi cancelada guard !Task.isCancelled else { return "Cancelado" } // Simula trabalho longo try? await Task.sleep(nanoseconds: 2_000_000_000) return "Concluído"}Processamento paralelo com TaskGroup
// Carregando várias imagens em paralelofunc loadImages(urls: [URL]) async throws -> [UIImage] { return try await withThrowingTaskGroup(of: UIImage.self) { group in var images: [UIImage] = [] images.reserveCapacity(urls.count) for url in urls { group.addTask { let (data, _) = try await URLSession.shared.data(from: url) guard let image = UIImage(data: data) else { throw URLError(.cannotDecodeContentData) } return image } } // Coletando resultados à medida que ficam prontos for try await image in group { images.append(image) } return images }}Importante: TaskGroup gerencia automaticamente o ciclo de vida das tarefas filhas