Do-Catch es una construcción del lenguaje Swift para el manejo de errores que captura excepciones lanzadas mediante throw y ejecuta el bloque de código correspondiente. A diferencia del try-catch tradicional en otros lenguajes, Swift requiere marcar explícitamente las funciones que pueden lanzar un error con el modificador throws. Según Swift.org, 2026, Do-Catch es el mecanismo principal de manejo de errores en Swift, proporcionando seguridad de tipos.
Puntos clave
Do-Catch es una construcción en Swift que consiste en un bloque do, dentro del cual se ejecuta código capaz de lanzar un error, y uno o más bloques catch que manejan dicho error. El bloque do contiene llamadas a funciones throwing marcadas con try, y los bloques catch coinciden con el error por tipo.
Swift implementa un modelo de manejo estructurado de errores, diferente de las excepciones en Objective-C. Aquí un error no es una excepción con desenrollado de pila, sino un valor que cumple con el protocolo Error. Lanzar un error mediante throw transfiere el control al bloque catch más cercano sin la sobrecarga del desenrollado de pila.
Una característica clave de Swift es el manejo explícito. El compilador no permite llamar a una función throwing sin try, do-catch o un mecanismo alternativo (try?, try!). Esto elimina situaciones donde un error pasa desapercibido.
En el centro del manejo de errores en Swift está el protocolo Error. Cualquier tipo que cumpla con este protocolo puede ser lanzado mediante throw. Los errores se definen típicamente como un enum que cumple con Error.
Error es un protocolo vacío (marcador). No requiere implementación de métodos, solo conformidad. El compilador de Swift usa Error para verificación estática: una función con throws solo puede lanzar un valor que cumpla con Error.
Una función marcada con throws debe ser llamada con try. Si ocurre un throw dentro de dicha función, el control se transfiere al do-catch que la llamó. Si el error no se maneja en ningún punto de la cadena de llamadas, se propaga al nivel 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 es un modificador para funciones que aceptan un closure throwing como parámetro. Si el closure pasado no lanza un error, la función rethrows se puede llamar sin try. Esto permite escribir funciones genéricas de orden superior compatibles con closures throwing y no throwing.
Swift soporta múltiples bloques catch con coincidencia de errores por tipo. Esto es similar a when en Kotlin o un switch por tipo: el primer catch que coincide se ejecuta, el resto se omiten.
Cada bloque catch puede contener un patrón que coincida con un tipo específico de error. Swift verifica los bloques en orden, por lo que los tipos más específicos deben ir antes que los generales. Si ningún patrón coincide, se ejecuta el bloque catch sin patrón.
La seguridad de tipos de Do-Catch permite manejar cada error por separado o combinar varios tipos en un bloque mediante coincidencia de patrones separada por comas. Esto elimina las engorrosas cadenas if-else típicas de Objective-C, donde el análisis de errores se realizaba mediante códigos de retorno o NSError con verificación de dominio y código.
Swift también soporta catch where — coincidencia con una condición adicional. Por ejemplo, se pueden filtrar errores por un código o texto específico: catch URLError where error.code == .notConnectedToInternet. Esto reduce el número de bloques catch manteniendo la precisión.
Para depurar funciones throwing, Swift proporciona una distinción entre errores y excepciones. Un error de Swift es un valor de retorno que no requiere desenrollado de pila. Las excepciones de Objective-C (@try/@catch) funcionan a nivel de runtime y se usan solo para fallos fatales. Do-Catch maneja errores, no excepciones, lo que lo hace predecible y eficiente.
Al desarrollar bibliotecas y SDKs, es importante recordar que las funciones throwing son parte del contrato público. El tipo de error no se especifica en la firma, por lo que documente qué errores puede lanzar una función en comentarios o mediante enum similares a Result. Esto ayuda a los usuarios de la API a escribir bloques catch correctos sin necesidad de revisar la implementación.
En el contexto de la programación asíncrona, Do-Catch con async/await resuelve el problema del callback hell. Anteriormente en Swift, el manejo de errores en código asíncrono requería closures anidados con verificación de Error? en los completion handlers. Con async/await y Do-Catch, el código asíncrono throwing se ve como código síncrono, simplificando la lectura y el mantenimiento de cadenas de solicitudes complejas con manejo de errores en cada paso.
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("Error desconocido: \(error)")
}
Swift ofrece tres formas de llamar a funciones throwing: try, try? y try!. Cada opción resuelve una tarea específica y tiene sus limitaciones.
try se usa dentro de un bloque do, y el error se maneja en catch. Esta es la forma principal de llamar a funciones throwing. El compilador requiere que try esté en un contexto donde el error pueda ser capturado.
try? convierte el resultado de una función throwing en un Optional. Si la función lanza un error, try? devuelve nil, de lo contrario devuelve un Optional con el valor exitoso. Útil para llamadas donde el error se puede ignorar pero se necesita un indicador de éxito.
try! suprime el manejo de errores. Si la función throwing lanza un error, la aplicación termina con un error de runtime. Use try! solo cuando esté absolutamente seguro de que el error es imposible — por ejemplo, al cargar un recurso incluido.
// try? — ignoramos el error, obtenemos nil en fallo
if let data = try? Data(contentsOf: url) {
processData(data)
}
// try! — solo si el error es garantizadamente imposible
let bundled = try! String(contentsOfFile: "Assets/default.txt")
// try — opción estándar en do-catch
do {
let result = try performNetworkRequest()
updateUI(result)
} catch {
showError(error)
}
Do-Catch se usa activamente en el desarrollo iOS para trabajar con APIs del sistema. Consideremos escenarios típicos: trabajo con el sistema de archivos, Core Data y solicitudes de red.
Muchos métodos de FileManager son throwing. Do-Catch permite manejar correctamente la ausencia de un archivo, la ocupación de un recurso o la falta de permisos.
El análisis de JSON mediante JSONDecoder es una operación throwing. Do-Catch captura errores de decodificación y fallos de red por separado, proporcionando al usuario un mensaje de error preciso.
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)
}
// Llamada con manejo
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)
}
Los desarrolladores, especialmente aquellos que vienen de otros lenguajes, suelen cometer errores característicos al usar Do-Catch. Veamos los más comunes.
Preguntas frecuentes
En Swift, un error es un valor que cumple con el protocolo Error, no una excepción con desenrollado de pila. Las funciones throwing deben marcarse explícitamente con throws, y el compilador requiere try al llamarlas — esto elimina errores no manejados en tiempo de compilación.
Sí, las funciones async también pueden ser throws, y do-catch funciona con ellas. Llamar a una función async throwing requiere try await dentro de un bloque do. Esta es la forma estándar de manejar errores en código asíncrono de Swift.
Hay alternativas: try? convierte el error en nil, try! provoca un crash en caso de error, y rethrows permite propagar un error desde un closure. Do-catch sigue siendo la forma principal de manejo explícito.
Swift no tipifica los errores lanzados — cualquier función throwing puede lanzar cualquier tipo que cumpla con Error. Separe el manejo mediante coincidencia en catch por tipos específicos de error.
Sí, es una buena práctica. Defina AppError como un enum que cumpla con Error y convierta los errores del sistema en errores de dominio. Esto unifica el manejo y aísla la capa de aplicación de los detalles del sistema.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también