Swift Language
Manejo de errores
Buscar..
Observaciones
Para obtener más información sobre los errores, consulte El lenguaje de programación Swift .
Fundamentos de manejo de errores
Las funciones en Swift pueden devolver valores, arrojar errores o ambos:
func reticulateSplines() // no return value and no error
func reticulateSplines() -> Int // always returns a value
func reticulateSplines() throws // no return value, but may throw an error
func reticulateSplines() throws -> Int // may either return a value or throw an error
Cualquier valor que cumpla con el protocolo ErrorType (incluidos los objetos NSError) se puede lanzar como un error. Las enumeraciones proporcionan una forma conveniente de definir errores personalizados:
enum NetworkError: ErrorType {
case Offline
case ServerError(String)
}
enum NetworkError: Error {
// Swift 3 dictates that enum cases should be `lowerCamelCase`
case offline
case serverError(String)
}
Un error indica una falla no fatal durante la ejecución del programa, y se maneja con las construcciones especializadas de flujo de control do
/ catch
, throw
, y try
.
func fetchResource(resource: NSURL) throws -> String {
if let (statusCode, responseString) = /* ...from elsewhere...*/ {
if case 500..<600 = statusCode {
throw NetworkError.serverError(responseString)
} else {
return responseString
}
} else {
throw NetworkError.offline
}
}
Los errores pueden ser atrapados con do
/ catch
:
do {
let response = try fetchResource(resURL)
// If fetchResource() didn't throw an error, execution continues here:
print("Got response: \(response)")
...
} catch {
// If an error is thrown, we can handle it here.
print("Whoops, couldn't fetch resource: \(error)")
}
Cualquier función que pueda lanzar un error debe ser llamada usando try
, try?
, o try!
:
// error: call can throw but is not marked with 'try'
let response = fetchResource(resURL)
// "try" works within do/catch, or within another throwing function:
do {
let response = try fetchResource(resURL)
} catch {
// Handle the error
}
func foo() throws {
// If an error is thrown, continue passing it up to the caller.
let response = try fetchResource(resURL)
}
// "try?" wraps the function's return value in an Optional (nil if an error was thrown).
if let response = try? fetchResource(resURL) {
// no error was thrown
}
// "try!" crashes the program at runtime if an error occurs.
let response = try! fetchResource(resURL)
Capturando diferentes tipos de error
Vamos a crear nuestro propio tipo de error para este ejemplo.
enum CustomError: ErrorType {
case SomeError
case AnotherError
}
func throwing() throws {
throw CustomError.SomeError
}
enum CustomError: Error {
case someError
case anotherError
}
func throwing() throws {
throw CustomError.someError
}
La sintaxis de Do-Catch permite capturar un error arrojado, y crea automáticamente un error
nombre constante disponible en el bloque catch
:
do {
try throwing()
} catch {
print(error)
}
También puedes declarar una variable tú mismo:
do {
try throwing()
} catch let oops {
print(oops)
}
También es posible encadenar diferentes declaraciones de catch
. Esto es conveniente si se pueden lanzar varios tipos de errores en el bloque Do.
Aquí, el Do-Catch intentará primero lanzar el error como CustomError
, luego como NSError
si el tipo personalizado no coincide.
do {
try somethingMayThrow()
} catch let custom as CustomError {
print(custom)
} catch let error as NSError {
print(error)
}
En Swift 3, no es necesario realizar una conversión explícita a NSError.
do {
try somethingMayThrow()
} catch let custom as CustomError {
print(custom)
} catch {
print(error)
}
Patrón de captura y cambio para el manejo explícito de errores
class Plane {
enum Emergency: ErrorType {
case NoFuel
case EngineFailure(reason: String)
case DamagedWing
}
var fuelInKilograms: Int
//... init and other methods not shown
func fly() throws {
// ...
if fuelInKilograms <= 0 {
// uh oh...
throw Emergency.NoFuel
}
}
}
En la clase cliente:
let airforceOne = Plane()
do {
try airforceOne.fly()
} catch let emergency as Plane.Emergency {
switch emergency {
case .NoFuel:
// call nearest airport for emergency landing
case .EngineFailure(let reason):
print(reason) // let the mechanic know the reason
case .DamagedWing:
// Assess the damage and determine if the president can make it
}
}
Deshabilitando la propagación de errores
Los creadores de Swift han puesto mucha atención en hacer que el lenguaje sea expresivo y el manejo de errores es exactamente eso, expresivo. Si intenta invocar una función que puede generar un error, la llamada a la función debe ir precedida por la palabra clave try. La palabra clave try no es mágica. Todo lo que hace es concienciar al desarrollador de la capacidad de lanzamiento de la función.
Por ejemplo, el siguiente código utiliza una función loadImage (atPath :), que carga el recurso de imagen en una ruta determinada o genera un error si la imagen no se puede cargar. En este caso, debido a que la imagen se envía con la aplicación, no se generará ningún error en el tiempo de ejecución, por lo que es apropiado deshabilitar la propagación de errores.
let photo = try! loadImage(atPath: "./Resources/John Appleseed.jpg")
Crear error personalizado con descripción localizada
Crear enum
de errores personalizados
enum RegistrationError: Error {
case invalidEmail
case invalidPassword
case invalidPhoneNumber
}
Cree la extension
de RegistrationError
para manejar la descripción localizada.
extension RegistrationError: LocalizedError {
public var errorDescription: String? {
switch self {
case .invalidEmail:
return NSLocalizedString("Description of invalid email address", comment: "Invalid Email")
case .invalidPassword:
return NSLocalizedString("Description of invalid password", comment: "Invalid Password")
case .invalidPhoneNumber:
return NSLocalizedString("Description of invalid phoneNumber", comment: "Invalid Phone Number")
}
}
}
Error de manejo:
let error: Error = RegistrationError.invalidEmail
print(error.localizedDescription)