Intento comprender la nueva cuestión de manejo de errores en Swift 2. Esto es lo que hice: Primero declare una enumeración de error:
enum SandwichError: ErrorType {
case NotMe
case DoItYourself
}
Y luego declaró un método que arroja un error (no una excepción amigos. Es un error). Aquí está ese método:
func makeMeSandwich(names: [String: String]) throws -> String {
guard let sandwich = names["sandwich"] else {
throw SandwichError.NotMe
}
return sandwich
}
El problema es del lado de la llamada. Aquí está el código que llama a este método:
let kitchen = ["sandwich": "ready", "breakfeast": "not ready"]
do {
let sandwich = try makeMeSandwich(kitchen)
print("i eat it \(sandwich)")
} catch SandwichError.NotMe {
print("Not me error")
} catch SandwichError.DoItYourself {
print("do it error")
}
Después de que el do
compilador de línea dice Errors thrown from here are not handled because the enclosing catch is not exhaustive
. Pero en mi opinión es exhaustivo porque solo hay dos casos SandwichError
enum.
Para las declaraciones de cambio regulares, Swift puede comprender que es exhaustivo cuando se maneja cada caso.
do
bloques en el nivel superior que no son exhaustivos: si envuelve el do en una función de no lanzar, generará el error.Respuestas:
Hay dos puntos importantes para el modelo de manejo de errores Swift 2: exhaustividad y resistencia. Juntos, se reducen a su
do
/catch
sentencia necesitando detectar todos los errores posibles, no solo los que sabe que puede lanzar.Tenga en cuenta que no declara qué tipos de errores puede lanzar una función, solo si arroja algo. Es un tipo de problema de cero uno-infinito: como alguien que define una función para que otros (incluido su yo futuro) lo usen, no quiere tener que hacer que cada cliente de su función se adapte a cada cambio en la implementación de su función, incluidos los errores que puede arrojar. Desea que el código que llama a su función sea resistente a dicho cambio.
Debido a que su función no puede decir qué tipo de errores arroja (o podría arrojar en el futuro), los
catch
bloques que detectan errores no saben qué tipos de errores podría arrojar. Por lo tanto, además de manejar los tipos de error que conoce, debe manejar los que no tiene con unacatch
declaración universal ; de esa manera, si su función cambia el conjunto de errores que arroja en el futuro, las personas que llaman aún captarán su erroresPero no nos quedemos ahí. Piensa en esta idea de resiliencia un poco más. De la forma en que diseñó su emparedado, debe describir los errores en cada lugar donde los usa. Eso significa que cada vez que cambia el conjunto de casos de error, tiene que cambiar cada lugar que los usa ... no es muy divertido.
La idea detrás de definir sus propios tipos de error es permitirle centralizar cosas como esas. Podría definir un
description
método para sus errores:Y luego, su código de manejo de errores puede pedirle a su tipo de error que se describa a sí mismo, ahora cada lugar donde maneja errores puede usar el mismo código y manejar posibles casos de errores futuros también.
Esto también allana el camino para que los tipos de error (o extensiones en ellos) admitan otras formas de informar errores; por ejemplo, podría tener una extensión en su tipo de error que sepa cómo presentar un
UIAlertController
informe de error a un usuario de iOS.fuente
error caught in main()
.- Entonces, aunque todo lo que ha dicho suena sensato, no puedo reproducir ese comportamiento.try
expresión en el código de producción, ya que puede causar un error de ejecución y hacer que su aplicación se bloqueetry!
. Además, podría decirse que hay casos de uso válidos y "seguros" para las diversas operaciones de "fuerza" en Swift (desenvolver, probar, etc.) incluso para el código de producción, si por condición previa o configuración ha eliminado de manera confiable la posibilidad de falla, podría Ser más razonable de cortocircuito a falla instantánea que escribir código de manejo de errores que no se pueda comprobarSandwichError
tiene sentido poner esa lógica dentro de la clase. Sin embargo, sospecho que para la mayoría de los errores, la lógica de manejo de errores no puede estar tan encapsulada. Esto se debe a que generalmente requiere el conocimiento del contexto de la persona que llama (ya sea para recuperarse, volver a intentarlo o informar un error en sentido ascendente, etc.). En otras palabras, sospecho que el patrón más común tendría que coincidir con tipos de error específicos de todos modos.Sospecho que esto simplemente no se ha implementado correctamente todavía. La Guía de programación Swift definitivamente parece implicar que el compilador puede inferir coincidencias exhaustivas "como una declaración de cambio". No hace mención de la necesidad de un general
catch
para ser exhaustivo.También notará que el error está en la
try
línea, no al final del bloque, es decir, en algún momento el compilador podrá determinar quétry
declaración en el bloque tiene tipos de excepciones no controladas.Sin embargo, la documentación es un poco ambigua. He hojeado el video 'Qué hay de nuevo en Swift' y no pude encontrar ninguna pista; Seguiré intentando.
Actualizar:
Ahora estamos en Beta 3 sin ningún indicio de inferencia ErrorType. Ahora creo que si esto se planeó alguna vez (y sigo pensando que fue en algún momento), el despacho dinámico en las extensiones de protocolo probablemente acabó.
Actualización Beta 4:
Xcode 7b4 agregó soporte para comentarios de documentos para
Throws:
, que "se debe usar para documentar qué errores se pueden lanzar y por qué". Supongo que esto al menos proporciona algún mecanismo para comunicar errores a los consumidores API. ¡Quién necesita un sistema de tipos cuando tienes documentación!Otra actualización:
Después de pasar un tiempo esperando la
ErrorType
inferencia automática y resolviendo cuáles serían las limitaciones de ese modelo, he cambiado de opinión: esto es lo que espero que Apple implemente en su lugar. Esencialmente:Otra actualización
La justificación del manejo de errores de Apple ahora está disponible aquí . También ha habido algunas discusiones interesantes sobre la lista de correo de evolución rápida . Esencialmente, John McCall se opone a los errores mecanografiados porque cree que la mayoría de las bibliotecas terminarán incluyendo un caso de error genérico de todos modos, y que es poco probable que los errores mecanografiados agreguen mucho al código aparte de repetitivo (utilizó el término 'farol aspiracional'). Chris Lattner dijo que está abierto a errores mecanografiados en Swift 3 si puede funcionar con el modelo de resiliencia.
fuente
A Swift le preocupa que su declaración de caso no cubra todos los casos, para solucionarlo debe crear un caso predeterminado:
fuente
catch
declaraciones.func method() throws(YourErrorEnum)
, o inclusothrows(YourEnum.Error1, .Error2, .Error3)
para que sepa lo que se puede lanzarTambién me decepcionó la falta de tipo que una función puede lanzar, pero ahora lo entiendo gracias a @rickster y lo resumiré así: digamos que podríamos especificar el tipo que arroja una función, tendríamos algo como esto:
El problema es que incluso si no cambiamos nada en myFunctionThatThrows, si solo agregamos un caso de error a MyError:
estamos jodidos porque nuestro do / try / catch ya no es exhaustivo, así como cualquier otro lugar donde llamamos funciones que lanzan MyError
fuente
catch {}
embargo, A al final de cada bloque es posiblemente peor. Espero que el compilador finalmente infiera los tipos de error automáticamente donde pueda, pero no he podido confirmar.Ahora validar número:
fuente
Crea una enumeración como esta:
Crear método como:
Ahora verifique si el error está ahí o no y manejarlo:
fuente