Lição: 53: Confiabilidade em Swift com async/await
Swift introduziu um novo modelo de concorrência com o lançamento do Swift 5.5, oferecendo uma abordagem mais simplificada para lidar com código assíncrono. Este novo modelo utiliza as palavras-chave async
e await
, facilitando a escrita de código assíncrono limpo e eficiente. Nesta aula, vamos explorar os conceitos básicos da concorrência em Swift e fornecer exemplos para ilustrar seu poder.
O que é Concorrência?
Concorrência é a capacidade de executar múltiplas tarefas ao mesmo tempo. Em Swift, isso é particularmente importante ao lidar com operações que podem demorar, como requisições de rede ou consultas a bancos de dados. O modelo async/await permite que você escreva código assíncrono de uma maneira que se assemelha ao código síncrono, o que ajuda a torná-lo mais fácil de entender e manter.
Conceitos Básicos
Funções Assíncronas
Para definir uma função assíncrona em Swift, utilize a palavra-chave async
. Aqui está um exemplo simples:
func buscarDados() async -> String {
// Simula uma chamada de rede com um atraso
try? await Task.sleep(nanoseconds: 2_000_000_000) // Dorme por 2 segundos
return "Dados buscados!"
}
No exemplo acima, buscarDados
é uma função assíncrona que simula uma chamada de rede atrasada usando Task.sleep
.
Chamando Funções Assíncronas
Para chamar uma função assíncrona, você deve usar a palavra-chave await
. Isso informa ao compilador que você está aguardando a operação assíncrona ser concluída.
func carregarConteudo() async {
let dados = await buscarDados()
print(dados) // Saída: Dados buscados!
}
Trata de Erros
Quando você lida com operações assíncronas que podem gerar erros, pode combinar async
com throws
. Aqui está um exemplo:
enum ErroDeDados: Error {
case erroAoBuscar
}
func buscarDadosComErro() async throws -> String {
// Simula um erro potencial
throw ErroDeDados.erroAoBuscar
}
func carregarConteudoComTratamentoDeErros() async {
do {
let dados = try await buscarDadosComErro()
print(dados)
} catch {
print("Falha ao buscar dados: \(error)")
}
}
Grupos de Tarefas
Grupos de tarefas permitem que você crie um grupo de tarefas assíncronas relacionadas que podem ser executadas concorrentemente. Eles fornecem uma maneira de aguardar múltiplas tarefas e coletar seus resultados.
Aqui está um exemplo usando grupos de tarefas:
func buscarMultipleDados() async -> [String] {
await withTaskGroup(of: String.self) { grupo in
for i in 1...3 {
grupo.addTask {
try await buscarDadosComAtraso(i: i)
}
}
var resultados: [String] = []
for await resultado in grupo {
resultados.append(resultado)
}
return resultados
}
}
func buscarDadosComAtraso(i: Int) async throws -> String {
try await Task.sleep(nanoseconds: UInt64(i) * 1_000_000_000) // Dorme por i segundos
return "Dados buscados para a tarefa \(i)"
}
@main
struct MeuApp {
static func main() async {
let resultados = await buscarMultipleDados()
print(resultados) // Saída: Dados buscados para a tarefa 1, 2, 3
}
}
Neste exemplo, buscarMultipleDados
cria um grupo de tarefas, gerando múltiplas tarefas assíncronas que buscam dados concorrentemente. Os resultados são coletados e retornados ao final.
Concorrência Estruturada
O modelo de concorrência do Swift também introduz a concorrência estruturada, o que significa que as tarefas assíncronas podem ser definidas dentro de um contexto específico, regulando automaticamente seu ciclo de vida. Isso reduz as chances de vazamentos de recursos e garante que as tarefas sejam concluídas antes de passar para a próxima etapa.
Usando Task
Você pode criar uma Task
para executar operações assíncronas:
Task {
let resultado = await buscarDados()
print(resultado)
}
Isso cria uma tarefa leve executando em segundo plano, permitindo a execução concorrente.
Conclusão
A concorrência em Swift com async/await simplifica significativamente a maneira como escrevemos código assíncrono. Ela permite que os desenvolvedores escrevam código claro, manutenível e eficiente, enquanto gerenciam a complexidade que vem com a concorrência. Ao entender e utilizar esses recursos, você pode aprimorar suas aplicações Swift, tornando-as mais responsivas e amigáveis ao usuário.
Agora que você possui uma compreensão fundamental do modelo de concorrência do Swift, pode começar a incorporar essas técnicas em seus próprios projetos. Boa codificação!