Solución:
Swift 2 y 3
Las cosas han cambiado un poco en Swift 2, ya que hay un nuevo mecanismo de manejo de errores, que es algo más similar a las excepciones pero diferente en los detalles.
1. Indica la posibilidad de error
Si la función / método quiere indicar que puede arrojar un error, debe contener throws
palabra clave como esta
func summonDefaultDragon() throws -> Dragon
Nota: no hay ninguna especificación para el tipo de error que la función realmente puede generar. Esta declaración simplemente establece que la función puede lanzar una instancia de cualquier tipo que implemente ErrorType o no lanzar en absoluto.
2. Función de invocación que puede generar errores
Para invocar la función, debe usar la palabra clave try, como esta
try summonDefaultDragon()
esta línea normalmente debería estar presente bloque do-catch como este
do {
let dragon = try summonDefaultDragon()
} catch DragonError.dragonIsMissing {
// Some specific-case error-handling
} catch DragonError.notEnoughMana(let manaRequired) {
// Other specific-case error-handlng
} catch {
// Catch all error-handling
}
Nota: la cláusula de captura utiliza todas las potentes funciones de la coincidencia de patrones Swift, por lo que es muy flexible aquí.
Puede decidir propagar el error, si está llamando a una función de lanzamiento desde una función que está marcada con throws
palabra clave:
func fulfill(quest: Quest) throws {
let dragon = try summonDefaultDragon()
quest.ride(dragon)
}
Alternativamente, puede llamar a la función de lanzamiento usando try?
:
let dragonOrNil = try? summonDefaultDragon()
De esta manera, obtiene el valor de retorno o nulo, si se produjo algún error. De esta manera, no obtiene el objeto de error.
Lo que significa que también puedes combinar try?
con declaraciones útiles como:
if let dragon = try? summonDefaultDragon()
o
guard let dragon = try? summonDefaultDragon() else { ... }
Por último, puede decidir que sabe que el error no se producirá realmente (por ejemplo, porque ya ha comprobado que son requisitos previos) y utilizar try!
palabra clave:
let dragon = try! summonDefaultDragon()
Si la función realmente arroja un error, obtendrá un error de tiempo de ejecución en su aplicación y la aplicación terminará.
3. Lanzar un error
Para lanzar un error, usa una palabra clave como esta.
throw DragonError.dragonIsMissing
Puedes lanzar cualquier cosa que se ajuste a ErrorType
protocolo. Para principiantes NSError
cumple con este protocolo, pero probablemente le gustaría ir con enum-based ErrorType
que le permite agrupar varios errores relacionados, potencialmente con datos adicionales, como este
enum DragonError: ErrorType {
case dragonIsMissing
case notEnoughMana(requiredMana: Int)
...
}
Las principales diferencias entre el nuevo mecanismo de error Swift 2 y 3 y las excepciones de estilo Java / C # / C ++ son las siguientes:
- La sintaxis es un poco diferente:
do-catch
+try
+defer
vs tradicionaltry-catch-finally
sintaxis. - El manejo de excepciones generalmente implica un tiempo de ejecución mucho mayor en la ruta de excepción que en la ruta de éxito. Este no es el caso de los errores de Swift 2.0, donde la ruta de éxito y la ruta de error cuestan aproximadamente lo mismo.
- Se debe declarar todo el código que arroja errores, mientras que las excepciones pueden haberse lanzado desde cualquier lugar. Todos los errores son “excepciones comprobadas” en la nomenclatura de Java. Sin embargo, a diferencia de Java, no especifica los posibles errores lanzados.
- Las excepciones rápidas no son compatibles con las excepciones de ObjC. Tu
do-catch
block no detectará ninguna NSException, y viceversa, para eso debe usar ObjC. - Las excepciones rápidas son compatibles con Cocoa
NSError
convenciones del método de devoluciónfalse
(porBool
funciones de retorno) onil
(porAnyObject
devolviendo funciones) y pasandoNSErrorPointer
con detalles de error.
Como azúcar sintético adicional para facilitar el manejo de errores, hay dos conceptos más
- acciones diferidas (usando
defer
palabra clave) que le permiten lograr el mismo efecto que los bloques finalmente en Java / C # / etc. - declaración de guardia (usando
guard
palabra clave) que le permiten escribir un poco menos de código if / else que en el código normal de verificación / señalización de errores.
Rápido 1
Errores de tiempo de ejecución:
Como sugiere Leandros para manejar errores en tiempo de ejecución (como problemas de conectividad de red, análisis de datos, apertura de archivos, etc.), debe usar NSError
como hiciste en ObjC, porque Foundation, AppKit, UIKit, etc. informan sus errores de esta manera. Así que es más una cuestión de marco que de lenguaje.
Otro patrón frecuente que se utiliza son los bloques de éxito / error del separador como en AFNetworking:
var sessionManager = AFHTTPSessionManager(baseURL: NSURL(string: "yavin4.yavin.planets"))
sessionManager.HEAD("/api/destoryDeathStar", parameters: xwingSquad,
success: { (NSURLSessionDataTask) -> Void in
println("Success")
},
failure:{ (NSURLSessionDataTask, NSError) -> Void in
println("Failure")
})
Aún así, el bloque de fallas recibió con frecuencia NSError
ejemplo, describiendo el error.
Errores del programador:
Para los errores del programador (como el acceso fuera de los límites del elemento de la matriz, los argumentos no válidos pasados a una llamada de función, etc.), usó excepciones en ObjC. El lenguaje rápido no parece tener ningún soporte de idioma para excepciones (como throw
, catch
, etc palabra clave). Sin embargo, como sugiere la documentación, se ejecuta en el mismo tiempo de ejecución que ObjC y, por lo tanto, aún puede lanzar NSExceptions
como esto:
NSException(name: "SomeName", reason: "SomeReason", userInfo: nil).raise()
Simplemente no puede capturarlos en Swift puro, aunque puede optar por capturar excepciones en el código ObjC.
La pregunta es si debe lanzar excepciones para los errores del programador o, más bien, usar afirmaciones como Apple sugiere en la guía de idiomas.
Actualización 9 de junio de 2015 – Muy importante
Swift 2.0 viene con try
, throw
, y catch
palabras clave y la más emocionante es:
Swift traduce automáticamente los métodos Objective-C que producen errores en métodos que generan un error de acuerdo con la funcionalidad nativa de manejo de errores de Swift.
Nota: Los métodos que consumen errores, como los métodos delegados o los métodos que toman un controlador de finalización con un argumento de objeto NSError, no se convierten en métodos que se lanzan cuando los importa Swift.
Extracto de: Apple Inc. “Uso de Swift con Cocoa y Objective-C (Presentación de Swift 2)”. iBooks.
Ejemplo: (del libro)
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *URL = [NSURL fileURLWithPath:@"/path/to/file"];
NSError *error = nil;
BOOL success = [fileManager removeItemAtURL:URL error:&error];
if (!success && error){
NSLog(@"Error: %@", error.domain);
}
El equivalente en swift será:
let fileManager = NSFileManager.defaultManager()
let URL = NSURL.fileURLWithPath("path/to/file")
do {
try fileManager.removeItemAtURL(URL)
} catch let error as NSError {
print ("Error: (error.domain)")
}
Lanzar un error:
*errorPtr = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCannotOpenFile userInfo: nil]
Se propagará automáticamente a la persona que llama:
throw NSError(domain: NSURLErrorDomain, code: NSURLErrorCannotOpenFile, userInfo: nil)
De los libros de Apple, The Swift Programming Language, parece que los errores deben manejarse usando enum.
A continuación se muestra un ejemplo del libro.
enum ServerResponse {
case Result(String, String)
case Error(String)
}
let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")
switch success {
case let .Result(sunrise, sunset):
let serverResponse = "Sunrise is at (sunrise) and sunset is at (sunset)."
case let .Error(error):
let serverResponse = "Failure... (error)"
}
De: Apple Inc. “El lenguaje de programación Swift”. iBooks. https://itun.es/br/jEUH0.l
Actualizar
De los libros de noticias de Apple, “Uso de Swift con Cocoa y Objective-C”. Las excepciones en tiempo de ejecución no ocurren usando lenguajes rápidos, por eso no tienes try-catch. En su lugar, utiliza el encadenamiento opcional.
Aquí hay un fragmento del libro:
Por ejemplo, en el código que aparece a continuación, la primera y la segunda línea no se ejecutan porque la propiedad length y el método characterAtIndex: no existen en un objeto NSDate. Se infiere que la constante myLength es un Int opcional y se establece en nil. También puede usar una instrucción if-let para desenvolver condicionalmente el resultado de un método al que el objeto puede no responder, como se muestra en la línea tres
let myLength = myObject.length?
let myChar = myObject.characterAtIndex?(5)
if let fifthCharacter = myObject.characterAtIndex(5) {
println("Found (fifthCharacter) at index 5")
}
Extracto de: Apple Inc. “Uso de Swift con Cocoa y Objective-C”. iBooks. https://itun.es/br/1u3-0.l
Y los libros también lo alientan a usar el patrón de error cocoa de Objective-C (Objeto NSError)
Los informes de errores en Swift siguen el mismo patrón que en Objective-C, con el beneficio adicional de ofrecer valores de retorno opcionales. En el caso más simple, devuelve un valor bool de la función para indicar si tuvo éxito o no. Cuando necesite informar el motivo del error, puede agregar a la función un parámetro NSError out de tipo NSErrorPointer. Este tipo es aproximadamente equivalente al NSError ** de Objective-C, con seguridad de memoria adicional y escritura opcional. Puede usar el prefijo & operador para pasar una referencia a un tipo NSError opcional como un objeto NSErrorPointer, como se muestra en la lista de códigos a continuación.
var writeError : NSError?
let written = myString.writeToFile(path, atomically: false,
encoding: NSUTF8StringEncoding,
error: &writeError)
if !written {
if let error = writeError {
println("write failure: (error.localizedDescription)")
}
}
Extracto de: Apple Inc. “Uso de Swift con Cocoa y Objective-C”. iBooks. https://itun.es/br/1u3-0.l
No hay excepciones en Swift, similar al enfoque de Objective-C.
En desarrollo, puede utilizar assert
para detectar cualquier error que pueda aparecer y que deba solucionarse antes de pasar a producción.
El clásico NSError
el enfoque no se modifica, envía un NSErrorPointer
, que se llena.
Breve ejemplo:
var error: NSError?
var contents = NSFileManager.defaultManager().contentsOfDirectoryAtPath("/Users/leandros", error: &error)
if let error = error {
println("An error occurred (error)")
} else {
println("Contents: (contents)")
}