within unreachable try thrown throwing occur functions example errors catch calls because are swift swift2

swift - unreachable - Sintaxis rápida de do-try-catch



try catch swift 4 example (6)

A Swift le preocupa que su declaración de caso no cubra todos los casos, para solucionarlo debe crear un caso predeterminado:

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") } catch Default { print("Another Error") }

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 compilador do line diga que los 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 en SandwichError enum.

Para las declaraciones regulares de cambio, Swift puede comprender que es exhaustivo cuando se maneja cada caso.


Crea una enumeración como esta:

//Error Handling in swift enum spendingError : Error{ case minus case limit }

Crear método como:

func calculateSpending(morningSpending:Double,eveningSpending:Double) throws ->Double{ if morningSpending < 0 || eveningSpending < 0{ throw spendingError.minus } if (morningSpending + eveningSpending) > 100{ throw spendingError.limit } return morningSpending + eveningSpending }

Ahora verifique si el error está ahí o no y manejarlo:

do{ try calculateSpending(morningSpending: 60, eveningSpending: 50) } catch spendingError.minus{ print("This is not possible...") } catch spendingError.limit{ print("Limit reached...") }


Hay dos puntos importantes en el modelo de manejo de errores Swift 2: exhaustividad y resistencia. Juntos, se reducen a su declaración do / catch que necesita 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 bloques catch que capturan errores no saben qué tipos de errores podrían arrojar. Por lo tanto, además de manejar los tipos de error que conoce, debe manejar los que no tiene con una declaración de catch universal; de esa manera, si su función cambia el conjunto de errores que arroja en el futuro, las personas que llaman seguirán captando sus errores

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") } catch let error { print(error.localizedDescription) }

Pero 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 método de description para sus errores:

extension SandwichError: CustomStringConvertible { var description: String { switch self { case NotMe: return "Not me error" case DoItYourself: return "Try sudo" } } }

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.

do { let sandwich = try makeMeSandwich(kitchen) print("i eat it /(sandwich)") } catch let error as SandwichError { print(error.description) } catch { print("i dunno") }

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 para informar el error a un usuario de iOS .


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 ninguna mención de la necesidad de una catch general para ser exhaustivo.

También notará que el error está en la línea de try , no en el final del bloque, es decir, en algún momento el compilador podrá determinar qué declaración de try en el bloque tiene tipos de excepción no controlados.

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 planificó 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 de 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 de API. ¡Quién necesita un sistema de tipos cuando tienes documentación!

Otra actualización:

Después de pasar un tiempo esperando la inferencia automática de ErrorType , y ErrorType cuáles serían las limitaciones de ese modelo, he cambiado de opinión: this es lo que espero que Apple implemente en su lugar. Esencialmente:

// allow us to do this: func myFunction() throws -> Int // or this: func myFunction() throws CustomError -> Int // but not this: func myFunction() throws CustomErrorOne, CustomErrorTwo -> Int

Otra actualización

La justificación del manejo de errores de Apple ahora está disponible here . También ha habido algunas discusiones interesantes sobre la lista de correo de swift-evolution . 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.


Tambié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:

enum MyError: ErrorType { case ErrorA, ErrorB } func myFunctionThatThrows() throws MyError { ...throw .ErrorA...throw .ErrorB... } do { try myFunctionThatThrows() } case .ErrorA { ... } case .ErrorB { ... }

El problema es que incluso si no cambiamos nada en myFunctionThatThrows, si solo agregamos un caso de error a MyError:

enum MyError: ErrorType { case ErrorA, ErrorB, ErrorC }

estamos jodidos porque nuestro do / try / catch ya no es exhaustivo, así como cualquier otro lugar donde llamamos funciones que lanzan MyError


enum NumberError: Error { case NegativeNumber(number: Int) case ZeroNumber case OddNumber(number: Int) } extension NumberError: CustomStringConvertible { var description: String { switch self { case .NegativeNumber(let number): return "Negative number /(number) is Passed." case .OddNumber(let number): return "Odd number /(number) is Passed." case .ZeroNumber: return "Zero is Passed." } } } func validateEvenNumber(_ number: Int) throws ->Int { if number == 0 { throw NumberError.ZeroNumber } else if number < 0 { throw NumberError.NegativeNumber(number: number) } else if number % 2 == 1 { throw NumberError.OddNumber(number: number) } return number }

Ahora validar número:

do { let number = try validateEvenNumber(0) print("Valid Even Number: /(number)") } catch let error as NumberError { print(error.description) }