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 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.
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.
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.
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.
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 é 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.
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.
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.
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.
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)")
}
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 é 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? 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! 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.
// 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 é 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.
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.
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.
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)
}
Desenvolvedores, especialmente aqueles vindos de outras linguagens, frequentemente cometem erros característicos ao usar Do-Catch. Vamos ver os mais comuns.
Perguntas frequentes
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.
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.
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.
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.
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
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.
Leia também