Swift soporta un sistema estricto de manejo de errores a través del protocolo Error y las construcciones throw, try, catch. Puedes definir tus propios tipos de errores heredando de Error:
enum NetworkError: Error { case noInternet case serverError(code: Int) case unknown }
Las funciones que pueden lanzar un error se declaran con throws:
func fetchData() throws -> Data { // ... throw NetworkError.noInternet }
Los errores se pueden manejar con un bloque do-catch:
do { let data = try fetchData() // Trabajar con los datos } catch NetworkError.noInternet { print("No hay internet") } catch { print("Otro error: \(error)") }
Un enfoque alternativo es el tipo Result<T, Error>, que permite devolver el resultado o un error sin necesidad de try-catch:
func fetchData() -> Result<Data, NetworkError> { // ... return .failure(.noInternet) } let result = fetchData() switch result { case .success(let data): // OK case .failure(let err): // Manejo del error }
Cuándo usar:
try/catch si el error es crítico y no se puede evitar su manejo.Result si la función es asíncrona, o cuando es conveniente pasar el error "fuera" sin excepciones.Pregunta: "¿Se pueden lanzar y atrapar errores de cualquier tipo, por ejemplo, cadenas o números?"
Respuesta: No, en Swift solo se pueden lanzar tipos que correspondan al protocolo Error.
// Incorrecto: throw "StringError" // El compilador no permitirá esto // Correcto: struct MyError: Error {} throw MyError()
Historia
En un proyecto de cliente de REST API, se lanzaba un error como cadena (throw "No data"). El código compilaba en JavaScript, pero después de la traducción a Swift, surgió un error fatal de compilación.
Historia
Un desarrollador devolvía errores a través de valores opcionales (return nil en caso de error), en lugar de usar throw/Result. Como resultado, se perdieron detalles de los errores, y era difícil manejarlos correctamente; se producían fallos silenciosos.
Historia
El análisis mostró que en varios lugares de la aplicación, errores similares no se agruparon en un solo tipo de Error. Como resultado, las aplicaciones manejaban de manera diferente fallos similares, y la UI mostraba mensajes diferentes para el mismo error, lo que dificultaba el mantenimiento y las pruebas.