Do-Catch: o que é, construção e tratamento de erros em Swift

Autor: IT Sectr Publicado: 2026-05-26 Tempo de leitura: 8 min

Do-Catch é uma construção da linguagem Swift para tratamento de erros que captura exceções lançadas via throw e executa o bloco de código correspondente. Diferente do try-catch tradicional em outras linguagens, Swift exige marcação explícita das funções que podem lançar um erro com o modificador throws. De acordo com Swift.org, 2026, Do-Catch é o principal mecanismo de tratamento de erros em Swift, fornecendo segurança de tipos.

Principais pontos

  • Do-Catch é uma construção Swift que captura erros de blocos com try e throw.
  • throws é um marcador de função que indica que ela pode lançar um erro.
  • try é a palavra-chave para chamar uma função throwing dentro de um bloco do.
  • catch é o bloco de tratamento de erros com correspondência de padrões por tipo.
  • try? e try! são formas alternativas que convertem erros em nil ou causam um crash.

O que é Do-Catch?

Do-Catch é uma construção em Swift que consiste em um bloco do, dentro do qual o código capaz de lançar um erro é executado, e um ou mais blocos catch que tratam esse erro. O bloco do contém chamadas para funções throwing marcadas com try, e os blocos catch correspondem ao erro por tipo.

Swift implementa um modelo de tratamento estruturado de erros, diferente das exceções em Objective-C. Aqui um erro não é uma exceção com desenrolamento de pilha, mas um valor que está em conformidade com o protocolo Error. Lançar um erro via throw transfere o controle para o bloco catch mais próximo sem a sobrecarga do desenrolamento de pilha.

Uma característica fundamental do Swift é o tratamento explícito. O compilador não permite chamar uma função throwing sem try, do-catch ou um mecanismo alternativo (try?, try!). Isso elimina situações onde um erro passa despercebido.

Modelo de erros em Swift: protocolo Error e funções throwing

No centro do tratamento de erros em Swift está o protocolo Error. Qualquer tipo que esteja em conformidade com este protocolo pode ser lançado via throw. Os erros são tipicamente definidos como um enum em conformidade com Error.

Protocolo Error

Error é um protocolo vazio (marcador). Ele não requer implementação de métodos, apenas conformidade. O compilador Swift usa Error para verificação estática: uma função com throws só pode lançar um valor que esteja em conformidade com Error.

Funções Throwing

Uma função marcada com throws deve ser chamada com try. Se um throw ocorrer dentro dessa função, o controle é transferido para o do-catch que a chamou. Se o erro não for tratado em nenhum lugar da cadeia de chamadas, ele é propagado para o nível superior.

swift
enum FileError: Error {
    case notFound
    case permissionDenied
    case corrupted(String)
}

func readFile(path: String) throws -> String {
    guard FileManager.default.fileExists(atPath: path) else {
        throw FileError.notFound
    }
    return try String(contentsOfFile: path)
}

Rethrows

rethrows é um modificador para funções que aceitam um closure throwing como parâmetro. Se o closure passado não lançar um erro, a função rethrows pode ser chamada sem try. Isso permite escrever funções genéricas de ordem superior compatíveis com closures throwing e não throwing.

Sintaxe do Do-Catch: múltiplos blocos catch

Swift suporta múltiplos blocos catch com correspondência de erros por tipo. Isso é semelhante ao when em Kotlin ou um switch por tipo: o primeiro catch correspondente é executado, os demais são ignorados.

Correspondência por tipo

Cada bloco catch pode conter um padrão que corresponde a um tipo específico de erro. Swift verifica os blocos em ordem, portanto tipos mais específicos devem vir antes dos gerais. Se nenhum padrão corresponder, o bloco catch sem padrão é executado.

Tratamento de múltiplos tipos

A segurança de tipos do Do-Catch permite tratar cada erro separadamente ou combinar vários tipos em um bloco através de correspondência de padrões separada por vírgulas. Isso elimina as cadelas if-else complicadas típicas do Objective-C, onde a análise de erros era feita através de códigos de retorno ou NSError com verificação de domínio e código.

Swift também suporta catch where — correspondência com uma condição adicional. Por exemplo, você pode filtrar erros por um código ou texto específico: catch URLError where error.code == .notConnectedToInternet. Isso reduz o número de blocos catch mantendo a precisão.

Para depurar funções throwing, Swift fornece uma distinção entre erros e exceções. Um erro Swift é um valor de retorno que não requer desenrolamento de pilha. Exceções Objective-C (@try/@catch) funcionam em nível de runtime e são usadas apenas para falhas fatais. Do-Catch trata erros, não exceções, tornando-o previsível e eficiente.

Ao desenvolver bibliotecas e SDKs, é importante lembrar que funções throwing fazem parte do contrato público. O tipo de erro não é especificado na assinatura, portanto documente quais erros uma função pode lançar em comentários ou através de enums semelhantes a Result. Isso ajuda os usuários da API a escrever blocos catch corretos sem precisar olhar a implementação.

No contexto da programação assíncrona, Do-Catch com async/await resolve o problema do callback hell. Anteriormente em Swift, o tratamento de erros em código assíncrono exigia closures aninhados com verificação de Error? em completion handlers. Com async/await e Do-Catch, o código assíncrono throwing parece código síncrono, simplificando a leitura e manutenção de cadeias de requisições complexas com tratamento de erros em cada etapa.

swift
do {
    let content = try readFile(path: "/data/config.json")
    process(content)
} catch FileError.notFound {
    createDefaultConfig()
} catch FileError.permissionDenied {
    requestAccess()
} catch FileError.corrupted(let detail) {
    logCorruption(detail)
} catch {
    print("Erro desconhecido: \(error)")
}

Variações de try: try, try?, try! e quando usá-los

Swift oferece três formas de chamar funções throwing: try, try? e try!. Cada opção resolve uma tarefa específica e tem suas limitações.

try — Chamada padrão

try é usado dentro de um bloco do, e o erro é tratado no catch. Esta é a forma principal de chamar funções throwing. O compilador exige que try esteja em um contexto onde o erro possa ser capturado.

try? — Conversão para Optional

try? converte o resultado de uma função throwing para um Optional. Se a função lançar um erro, try? retorna nil, caso contrário retorna um Optional com o valor bem-sucedido. Útil para chamadas onde o erro pode ser ignorado, mas um indicador de sucesso é necessário.

try! — Execução forçada

try! suprime o tratamento de erros. Se a função throwing lançar um erro, o aplicativo é encerrado com um erro de runtime. Use try! apenas quando você tiver certeza absoluta de que o erro é impossível — por exemplo, ao carregar um recurso embutido.

swift
// try? — ignoramos o erro, obtemos nil em falha
if let data = try? Data(contentsOf: url) {
    processData(data)
}

// try! — apenas se o erro for garantidamente impossível
let bundled = try! String(contentsOfFile: "Assets/default.txt")

// try — opção padrão em do-catch
do {
    let result = try performNetworkRequest()
    updateUI(result)
} catch {
    showError(error)
}

Do-Catch no desenvolvimento iOS: exemplos práticos

Do-Catch é usado ativamente no desenvolvimento iOS para trabalhar com APIs do sistema. Vamos considerar cenários típicos: trabalho com sistema de arquivos, Core Data e requisições de rede.

Sistema de arquivos

Muitos métodos do FileManager são throwing. Do-Catch permite tratar corretamente a ausência de arquivo, ocupação de recurso ou permissões insuficientes.

Requisições de rede com Codable

Analisar JSON através do JSONDecoder é uma operação throwing. Do-Catch captura erros de decodificação e falhas de rede separadamente, fornecendo ao usuário uma mensagem de erro precisa.

swift
struct User: Codable {
    let id: Int
    let name: String
}

func fetchUser(id: Int) async throws -> User {
    let url = URL(string: "https://api.example.com/users/\(id)")!
    let (data, _) = try await URLSession.shared.data(from: url)
    return try JSONDecoder().decode(User.self, from: data)
}

// Chamada com tratamento
do {
    let user = try await fetchUser(id: 42)
    showUser(user)
} catch let error as URLError {
    showNetworkAlert(error)
} catch let error as DecodingError {
    showParseError(error)
} catch {
    showGenericError(error)
}

Erros comuns com Do-Catch

Desenvolvedores, especialmente aqueles vindos de outras linguagens, frequentemente cometem erros característicos ao usar Do-Catch. Vamos ver os mais comuns.

  • Try esquecido — chamar uma função throwing sem try causa um erro de compilação. Swift não permite ignorar erros implicitamente.
  • Catch vazio — um bloco catch sem tratamento esconde o erro. Sempre registre ou trate o erro, mesmo que pareça impossível.
  • Catch sem correspondência — um único catch genérico para todos os erros perde os benefícios da segurança de tipos. Separe o tratamento por tipos usando múltiplos blocos.
  • Uso excessivo de try! — try! em código de produção é uma fonte de crashes inesperados. Use-o apenas para recursos embutidos ou testes.

Perguntas frequentes

Como o Do-Catch em Swift difere do try-catch em outras linguagens?

Em Swift, um erro é um valor que está em conformidade com o protocolo Error, não uma exceção com desenrolamento de pilha. Funções throwing devem ser explicitamente marcadas com throws, e o compilador exige try ao chamá-las — isso elimina erros não tratados em tempo de compilação.

Pode-se usar Do-Catch com async/await?

Sim, funções async também podem ser throws, e do-catch funciona com elas. Chamar uma função async throwing requer try await dentro de um bloco do. Esta é a forma padrão de tratar erros em código assíncrono Swift.

Como tratar um erro sem do-catch?

Existem alternativas: try? converte o erro em nil, try! causa um crash em caso de erro, e rethrows permite propagar um erro de um closure. Do-catch continua sendo a forma principal de tratamento explícito.

Uma função pode lançar diferentes tipos de erros?

Swift não tipifica os erros lançados — qualquer função throwing pode lançar qualquer tipo que esteja em conformidade com Error. Separe o tratamento através de correspondência em catch por tipos específicos de erro.

Devo encapsular todos os erros em um tipo personalizado?

Sim, é uma boa prática. Defina AppError como um enum em conformidade com Error e converta erros do sistema em erros de domínio. Isso unifica o tratamento e isola a camada de aplicação dos detalhes do sistema.

Resumo

  • Do-Catch é uma construção Swift para tratamento de erros com marcação obrigatória de throws em funções e try em chamadas.
  • Erros Swift são valores que estão em conformidade com o protocolo Error, não exceções com desenrolamento de pilha, proporcionando zero de sobrecarga quando não ocorre falha.
  • Os múltiplos catch permitem tratar diferentes tipos de erros separadamente com correspondência de padrões semelhante a switch.
  • try? converte um erro em nil para cenários simples, try! é uma chamada forçada com risco de crash, usado apenas para operações garantidas.
  • Do-Catch com async/await é a forma padrão de tratar erros em código assíncrono Swift usando try await.
  • Evite blocos catch vazios e uso excessivo de try! — isso esconde erros e leva a crashes inesperados em produção.

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também