← Swift EspañolChapter 10 of 13

Manejo de Errores

## Objetivos de Aprendizaje - Comprender el manejo de errores de Swift - Lanzar y capturar errores - Usar tipo Result - Manejar errores apropiadamente ## Protocolo Error ### Definir Errores ```swift enum ErrorValidacion: Error { case vacio case muyCorto case caracterInvalido } ``` ### Tipos de Error Personalizados ```swift enum ErrorRed: Error { case urlInvalida case sinConexion case tiempoAgotado case respuestaInvalida case errorServidor(Int) } ``` ## Lanzar Errores ### Usando throw ```swift func validar(nombre: String?) throws { guard let nombre = nombre else { throw ErrorValidacion.vacio } guard nombre.count >= 2 else { throw ErrorValidacion.muyCorto } guard nombre.allSatisfy({ $0.isLetter }) else { throw ErrorValidacion.caracterInvalido } } ``` ### Funciones que Lanzan ```swift func puedeLanzar() throws -> String { // Funcion que puede lanzar throw AlgundoError.ups return "Exito" } // vs func noPuedeLanzar() -> String { // Funcion que no puede lanzar return "Exito" } ``` ## Expresion Try ### try Basico ```swift do { let resultado = try validar(nombre: "Alicia") print("Valido: \(resultado)") } catch { print("Ocurrio un error") } ``` ### try? (Try Opcional) Devuelve nil en error: ```swift let resultado = try? validar(nombre: "A") // resultado es nil si se lanzo un error if let valido = try? validar(nombre: "Alicia") { print(valido) } ``` ### try! (Try Forzado) Crashea en error: ```swift let resultado = try! validar(nombre: "Alicia") // CRASHEA si se lanzo un error! ``` ## Clausulas Catch ### Catch Basico ```swift do { try validar(nombre: "") } catch { print("Validacion fallida") } ``` ### Capturar Errores Especificos ```swift do { try validar(nombre: "") } catch ErrorValidacion.vacio { print("El nombre no puede estar vacio") } catch ErrorValidacion.muyCorto { print("El nombre es muy corto") } catch ErrorValidacion.caracterInvalido { print("El nombre contiene caracteres invalidos") } ``` ### Capturar con Patron ```swift do { try obtenerDatos(de: "invalido") } catch ErrorRed.errorServidor(let codigo) { print("Error de servidor con codigo: \(codigo)") } catch ErrorRed.tiempoAgotado { print("La solicitud expire") } catch { print("Error desconocido: \(error)") } ``` ### Capturar Cualquier Error ```swift do { try operacionRisky() } catch let error as MiError { print("Capturado error especifico: \(error)") } catch { print("Capturado cualquier error: \(error)") } ``` ## Propagacion de Errores ### Propagar Errores ```swift func procesarEntradaUsuario(_ entrada: String?) throws { guard let nombre = entrada else { throw ErrorValidacion.vacio } try validar(nombre: nombre) // Errores se propagan } do { try procesarEntradaUsuario(nil) } catch { print("Manejado en nivel superior: \(error)") } ``` ### Rethrowing ```swift func manejarErrores(_ operacion: () throws -> Void) rethrows { do { try operacion() } catch { print("Manejado: \(error)") } } ``` ## Tipo Result ### Enum Result ```swift enum Result { case exito(Exito) case fracaso(Fracaso) } ``` ### Usar Result ```swift func obtenerUsuario(id: Int) -> Result { if id > 0 { return .exito(Usuario(id: id, nombre: "Alicia")) } else { return .fracaso(ErrorRed.respuestaInvalida) } } ``` ### Manejar Result ```swift let resultado = obtenerUsuario(id: 1) switch resultado { case .exito(let usuario): print("Obtuve usuario: \(usuario.nombre)") case .fracaso(let error): print("Error: \(error)") } ``` ### Result con Opcional ```swift let resultado = Result.exito(Usuario(id: 1, nombre: "Alicia")) // Never significa que no puede fallar ``` ### Metodo get() ```swift let exito = Result.exito(42) let fracaso = Result.fracaso(ErrorRed.tiempoAgotado) try? exito.get() // Optional(42) try? fracaso.get() // nil ``` ## Ejecucion Diferida ### Declaracion defer ```swift func leerArchivo() { let archivo = abrirArchivo("datos.txt") defer { cerrarArchivo(archivo) // Siempre ejecutado antes del return } // Trabajar con archivo let contenido = leerContenido(archivo) // Archivo cerrado automaticamente aqui } ``` ### Multiples defers ```swift func ejemplo() { defer { print("1") } defer { print("2") } defer { print("3") } } // Salida: 3, 2, 1 (orden LIFO) ``` ### defer con Manejo de Errores ```swift func procesar() throws { let recurso = adquirirRecurso() defer { liberarRecurso(recurso) // Siempre liberado } try hacerTrabajo(recurso) // recurso liberado si hay exito o fracaso } ``` ## Manejo de Errores Personalizado ### Conformidad a Error ```swift struct ErrorPersonalizado: Error { let mensaje: String } throw ErrorPersonalizado(mensaje: "Algo salio mal") ``` ### LocalizedError ```swift struct ErrorArchivoNoEncontrado: Error, LocalizedError { let nombreArchivo: String var errorDescription: String? { return "Archivo no encontrado: \(nombreArchivo)" } } ``` ### Custom NSError ```swift extension ErrorPersonalizado: CustomNSError { var errorCode: Int { return 42 } var errorUserInfo: [String: Any] { return ["clavePersonalizada": "valorPersonalizado"] } } ``` ## Mejores Practicas ### Hacer ```swift // Usar tipos de error especificos enum ErrorApp: Error { case entradaInvalida case falloRed case noEncontrado } // Propagar errores cuando sea apropiado func cargarDatos() throws -> Data { let url = try obtenerURL() return try obtener(de: url) } // Usar Result para callbacks completacion(.exito(datos)) completacion(.fracaso(error)) ``` ### No Hacer ```swift // No tragar errores silenciosamente do { try operacion() } catch { // MAL: No hacer nada oculta bugs! } // No usar try! sin justificacion let valor = try! parse(json) // Solo si estas seguro ``` ## Patrones Comunes ### Manejo de Errores con Opcionales ```swift // Devuelve nil en lugar de lanzar func parsearSeguro(_ cadena: String) -> Int? { return Int(cadena) } let numero = parsearSeguro("42") ?? 0 ``` ### Encadenamiento Opcional Fallido ```swift struct Usuario { let nombre: String } func obtenerUsuario() throws -> Usuario { ... } let nombre = try? obtenerUsuario()?.nombre // nombre es nil si obtenerUsuario() devuelve nil o lanza ``` ### Transformar Errores ```swift enum ErrorApp: Error { case emailInvalido } func validar(email: String) throws { guard email.contains("@") else { throw ErrorApp.emailInvalido } } let email: String? = "test@ejemplo.com" try? email.flatMap { try? validar(email: $0) } // Aplana opcional y manejo de errores ``` ## Resumen - Los errores conforman el protocolo `Error` - Funciones que lanzan marcadas con `throws` - Usar `do-catch` para manejar errores - `try?` devuelve nil en error - `try!` crashea en error (usar con moderacion) - `Result` para operaciones que devuelven errores - `defer` para codigo de limpieza - Propagar errores con `rethrows` - Siempre manejar errores apropiadamente

Comments

Comments powered by Giscus

To enable comments, add your Giscus embed code here.

Learn more about Giscus →