Saltar al contenido

Manejo de errores en Swift-Language

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 tradicional try-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ón false (por Bool funciones de retorno) o nil (por AnyObject devolviendo funciones) y pasando NSErrorPointer 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)")
}
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *