Do-Catch: qué es, construcción y manejo de errores en Swift

Autor: IT Sectr Publicado: 2026-05-26 Tiempo de lectura: 8 min

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 de Swift que captura errores de bloques con try y throw.
  • throws es un marcador de función que indica que puede lanzar un error.
  • try es la palabra clave para llamar a una función throwing dentro de un bloque do.
  • catch es el bloque de manejo de errores con coincidencia de patrones por tipo.
  • try? y try! son formas alternativas que convierten errores en nil o provocan un crash.

¿Qué es Do-Catch?

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.

Modelo de errores en Swift: protocolo Error y funciones throwing

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.

Protocolo 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.

Funciones Throwing

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.

swift
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

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.

Sintaxis de Do-Catch: múltiples bloques catch

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.

Coincidencia por tipo

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.

Manejo de múltiples tipos

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.

swift
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)")
}

Variaciones de try: try, try?, try! y cuándo usarlos

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 — Llamada estándar

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? — Conversión a Optional

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! — Ejecución forzada

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.

swift
// 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 en desarrollo iOS: ejemplos prácticos

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.

Sistema de archivos

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.

Solicitudes de red con Codable

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.

swift
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)
}

Errores comunes con Do-Catch

Los desarrolladores, especialmente aquellos que vienen de otros lenguajes, suelen cometer errores característicos al usar Do-Catch. Veamos los más comunes.

  • Try olvidado — llamar a una función throwing sin try causa un error de compilación. Swift no permite ignorar errores implícitamente.
  • Catch vacío — un bloque catch sin manejo oculta el error. Siempre registre o maneje el error, incluso si parece imposible.
  • Catch sin coincidencia — un solo catch genérico para todos los errores pierde los beneficios de la seguridad de tipos. Separe el manejo por tipos usando múltiples bloques.
  • Uso excesivo de try! — try! en código de producción es una fuente de crashes inesperados. Úselo solo para recursos incluidos o pruebas.

Preguntas frecuentes

¿En qué se diferencia Do-Catch en Swift de try-catch en otros lenguajes?

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.

¿Se puede usar Do-Catch con async/await?

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.

¿Cómo manejar un error sin do-catch?

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.

¿Puede una función lanzar diferentes tipos de errores?

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.

¿Debo envolver todos los errores en un tipo personalizado?

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

  • Do-Catch es una construcción de Swift para el manejo de errores con marcado obligatorio de throws en funciones y try en llamadas.
  • Los errores de Swift son valores que cumplen con el protocolo Error, no excepciones con desenrollado de pila, lo que proporciona cero sobrecarga cuando no ocurre fallo.
  • Los múltiples catch permiten manejar diferentes tipos de errores por separado con coincidencia de patrones similar a switch.
  • try? convierte un error en nil para escenarios simples, try! es una llamada forzada con riesgo de crash, usado solo para operaciones garantizadas.
  • Do-Catch con async/await es la forma estándar de manejar errores en código asíncrono de Swift usando try await.
  • Evite bloques catch vacíos y el uso excesivo de try! — esto oculta errores y lleva a crashes inesperados en producción.

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.

Discutir el proyecto

Lea también