Tratamento de erros em Swift: blocos try/catch, throws e do-catch

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Tratamento de Erros em Swift: try/catch e Além



O desenvolvimento para iOS e macOS requer um gerenciamento confiável de erros. O Swift fornece um mecanismo poderoso e elegante para tratamento de falhas, baseado nas palavras-chave throws, try, catch e do. Neste artigo, vamos analisar como tratar erros corretamente, escrever código legível e evitar armadilhas comuns.



1. Fundamentos: Protocolo Error e a palavra-chave throws



Qualquer erro em Swift deve estar em conformidade com o protocolo Error. Geralmente, usa-se uma enumeração (enum) para isso:



enum NetworkError: Error {    case badURL    case noData    case decodingFailed(String)}


Uma função que pode lançar um erro é marcada com a palavra-chave throws:



func fetchUser(from urlString: String) throws -> User {    guard let url = URL(string: urlString) else {        throw NetworkError.badURL    }    // ... lógica da requisição}


Agora, ao chamar essa função, o compilador obrigará você a tratar o possível erro.



2. Construção do-catch: Capturando Erros



A forma mais comum de tratamento é o bloco do-catch. Você coloca o código potencialmente perigoso no do, e no catch trata a falha:



do {    let user = try fetchUser(from: "https://api.example.com/user")    print("Usuário carregado: \\(user.name)")} catch NetworkError.badURL {    print("URL inválido")} catch NetworkError.noData {    print("O servidor não retornou dados")} catch NetworkError.decodingFailed(let message) {    print("Erro de decodificação: \\(message)")} catch {    print("Erro desconhecido: \\(error.localizedDescription)")}


Importante: o último bloco catch sem um tipo específico captura todos os erros restantes — você deve sempre adicioná-lo.



2.1. Correspondência de Padrões no catch



Você pode usar condições mais complexas:



do {    let result = try riskyOperation()} catch let error as NetworkError where error == .badURL {    print("Problema com o URL")} catch {    print(error)}


3. Alternativas: try? e try!



Nem sempre é necessário um tratamento completo. O Swift oferece duas abordagens simplificadas:



3.1. try? — Valor Opcional



Se o erro não for crítico, você pode transformar o resultado em um opcional. Em caso de falha, a função retornará nil:



let user = try? fetchUser(from: "https://example.com/user")// user tem o tipo User? — nil em caso de erro


Ideal para situações onde o erro pode ser simplesmente ignorado (por exemplo, carregamento de avatar).



3.2. try! — Execução Forçada



Use try! apenas quando tiver absoluta certeza de que não haverá erro. Caso contrário, ocorrerá uma falha no aplicativo:



let user = try! fetchUser(from: "https://valid-url.com/user")// Se o URL for inválido — o aplicativo irá travar


Aplique try! em testes ou em situações onde a falha é logicamente impossível.



4. Técnicas Avançadas: rethrows e deferred



4.1. rethrows para Funções de Ordem Superior



Se sua função aceita uma closure que pode lançar um erro, use rethrows. Isso permite não marcar sua própria função como throws se a closure não lançar um erro:



func process(_ closure: () throws -> Void) rethrows {    try closure()}

// Chamada sem closure throws — não requer do-catchprocess { print("Sem erros") }

// Chamada com closure throws — requer tratamentotry process { throw NetworkError.noData }


4.2. deferred: Limpeza Garantida



O bloco defer é executado em qualquer término da função (sucesso ou erro). É perfeito para fechar arquivos ou liberar recursos

Blogs

Book Recommendations