Manejo de errores en Swift: try/catch, throws y bloques do-catch

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Manejo de errores en Swift: try/catch y más



El desarrollo para iOS y macOS requiere una gestión fiable de errores. Swift proporciona un mecanismo potente y elegante para el manejo de fallos, basado en las palabras clave throws, try, catch y do. En este artículo, analizaremos cómo manejar errores correctamente, escribir código legible y evitar trampas comunes.



1. Fundamentos: el protocolo Error y la palabra clave throws



Cualquier error en Swift debe cumplir con el protocolo Error. Normalmente, para esto se utilizan enumeraciones (enum):



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


Una función que puede lanzar un error se marca con la palabra clave throws:



func fetchUser(from urlString: String) throws -> User {    guard let url = URL(string: urlString) else {        throw NetworkError.badURL    }    // ... lógica de la solicitud}


Ahora, al llamar a esta función, el compilador le obligará a manejar el posible error.



2. La construcción do-catch: captura de errores



La forma más común de manejo es el bloque do-catch. Coloca el código potencialmente peligroso en do, y en catch maneja el fallo:



do {    let user = try fetchUser(from: "https://api.example.com/user")    print("Usuario cargado: \\(user.name)")} catch NetworkError.badURL {    print("URL inválido")} catch NetworkError.noData {    print("El servidor no devolvió datos")} catch NetworkError.decodingFailed(let message) {    print("Error de decodificación: \\(message)")} catch {    print("Error desconocido: \\(error.localizedDescription)")}


Importante: el último bloque catch sin un tipo específico captura todos los errores restantes; siempre debería añadirse.



2.1. Coincidencia de patrones en catch



Puede usar condiciones más complejas:



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


3. Alternativas: try? y try!



No siempre se necesita un manejo completo. Swift ofrece dos enfoques simplificados:



3.1. try? — valor opcional



Si el error no es crítico, puede convertir el resultado en un opcional. En caso de fallo, la función devolverá nil:



let user = try? fetchUser(from: "https://example.com/user")// user tiene tipo User? — nil en caso de error


Ideal para situaciones donde el error simplemente puede ignorarse (por ejemplo, carga de avatar).



3.2. try! — ejecución forzada



Use try! solo cuando esté absolutamente seguro de que no habrá error. De lo contrario, la aplicación fallará:



let user = try! fetchUser(from: "https://valid-url.com/user")// Si la URL no es válida, la aplicación se bloqueará


Aplique try! en pruebas o en situaciones donde el fallo sea imposible según la lógica del programa.



4. Técnicas avanzadas: rethrows y deferred



4.1. rethrows para funciones de orden superior



Si su función acepta un closure que puede lanzar un error, use rethrows. Esto permite no marcar su propia función como throws si el closure no lanza un error:



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

// Llamada sin closure throws — no requiere do-catchprocess { print("Sin errores") }

// Llamada con closure throws — requiere manejotry process { throw NetworkError.noData }


4.2. deferred: limpieza garantizada



El bloque defer se ejecuta al finalizar la función (ya sea con éxito o error). Es perfecto para cerrar archivos o liberar recursos.

Blogs

Book Recommendations