Tratamento de erros em Swift: try/catch e técnicas avançadas

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 muito mais (nível avançado)

\n\n

O tratamento de erros é um dos tópicos principais no desenvolvimento em Swift. Se você já conhece o básico de do-catch e try?, é hora de avançar para o próximo nível. Neste artigo, abordaremos técnicas avançadas: trabalho com o protocolo Error, tipo Result, palavra-chave rethrows, além de como projetar corretamente uma hierarquia de erros em projetos reais iOS/macOS.

\n\n

Mergulho profundo no protocolo Error e erros personalizados

\n\n

Em Swift, qualquer erro deve estar em conformidade com o protocolo Error. No entanto, para tornar o código mais legível e sustentável, vale a pena criar suas próprias enumerações (enum) com casos aninhados e valores associados.

\n\n
enum NetworkError: Error {\n    case invalidURL\n    case noData\n    case decodingFailed(description: String)\n    case serverError(statusCode: Int)\n    case timeout(seconds: Double)\n}\n\n// Exemplo de uso\nfunc fetchUser(id: Int) throws -> User {\n    guard id > 0 else {\n        throw NetworkError.invalidURL\n    }\n    // ... lógica da requisição\n    if someCondition {\n        throw NetworkError.serverError(statusCode: 500)\n    }\n    return User()\n}
\n\n

Essa abordagem permite transmitir contexto adicional: código de erro, descrição ou tempo de espera. Isso é especialmente útil para registro de logs e depuração.

\n\n

Result: alternativa ao do-catch para código assíncrono

\n\n

O tipo Result<Success, Failure> é uma ferramenta poderosa que veio da programação funcional. Ele é ideal para APIs baseadas em callbacks, requisições de rede e operações assíncronas.

\n\n
enum DataError: Error {\n    case corrupted\n    case notFound\n}\n\nfunc loadImage(from url: URL, completion: @escaping (Result<UIImage, DataError>) -> Void) {\n    DispatchQueue.global().async {\n        // Simulação de carregamento\n        if arc4random_uniform(2) == 0 {\n            completion(.success(UIImage()))\n        } else {\n            completion(.failure(.notFound))\n        }\n    }\n}\n\n// Uso\nloadImage(from: someURL) { result in\n    switch result {\n    case .success(let image):\n        print("Imagem carregada: \\(image)")\n    case .failure(let error):\n        print("Erro: \\(error.localizedDescription)")\n    }\n}
\n\n

Result torna o código mais previsível e elimina a necessidade de lidar com valores opcionais com nil. Além disso, você pode usar .map e .flatMap para cadeias de transformações.

\n\n

Rethrows: quando a função "passa adiante" os erros

\n\n

A palavra-chave rethrows é um dos recursos mais subestimados do Swift. Ela permite escrever uma função que não lança erros por si só, mas os "propaga" se o closure passado for throws.

\n\n
func performOperation<T>(on array: [T], operation: (T) throws -> Bool) rethrows -> [T] {\n    var result: [T] = []\n    for element in array {\n        if try operation(element) {\n            result.append(element)\n        }\n    }\n    return result\n}\n\n// Sem erros (não precisa de try)\nlet numbers = [1, 2, 3, 4, 5]\nlet evenNumbers = performOperation(on: numbers) { $0.isMultiple(of: 2) }\nprint(evenNumbers) // [2, 4]\n\n// Com erro (precisa de try)\nenum ValidationError: Error { case negative }\nlet filtered = try performOperation(on: numbers) { value in\n    guard value > 0 else { throw ValidationError.negative }\n    return value % 2 == 0\n}
\n\n

rethrows torna a API flexível: o usuário pode passar tanto um closure comum (sem try) quanto um closure com throws (neste caso, será necessário try). Isso é frequentemente usado na biblioteca padrão do Swift — por exemplo, em map, filter e for

Blogs

Book Recommendations