try errors error enum else custom catch swift exception optional

errors - swift try else



¿Qué significa "error fatal: inesperadamente encontrado nulo al desenvolver un valor opcional"? (10)

Mi programa Swift se está EXC_BAD_INSTRUCTION con EXC_BAD_INSTRUCTION y este error. ¿Qué significa y cómo lo soluciono?

error fatal: inesperadamente encontrado nulo al desenvolver un valor opcional

Esta publicación está destinada a recopilar respuestas a problemas "inesperadamente encontrados", para que no estén dispersos y sean difíciles de encontrar. Siéntase libre de agregar su propia respuesta o edit la respuesta wiki existente.


TL; respuesta DR

Con muy pocas excepciones , esta regla es dorada:

Evite el uso de !

Declarar variable opcional ( ? ), No implícitamente opciones opcionales sin envolver (IUO) ( ! )

En otras palabras, más bien use:
var nameOfDaughter: String?

En vez de:
var nameOfDaughter: String!

Desenvuelva la variable opcional usando if let o guard let

Cualquiera de las variables de desenvolver así:

if let nameOfDaughter = nameOfDaughter { print("My daughters name is: /(nameOfDaughter)") }

O así:

guard let nameOfDaughter = nameOfDaughter else { return } print("My daughters name is: /(nameOfDaughter)")

Esta respuesta pretendía ser concisa, para una comprensión completa, lea la respuesta aceptada


Básicamente, trataste de usar un valor nulo en lugares donde Swift solo permite valores nulos, diciéndole al compilador que confíe en ti que nunca habrá un valor nulo allí, permitiendo así que tu aplicación se compile.

Hay varios escenarios que conducen a este tipo de error fatal:

  1. desenvolturas forzadas:

    let user = someVariable!

    Si someVariable es nulo, obtendrá un bloqueo. Al realizar un desenvolvimiento forzado, usted transfirió la responsabilidad de verificación nula del compilador a usted, básicamente al realizar un desenvolvimiento forzado, le garantiza al compilador que nunca tendrá valores nulos allí. ¿Y adivina qué sucede si de alguna manera un valor nulo termina en someVariable ?

    ¿Solución? Utilice el enlace opcional (también conocido como if-let), realice el procesamiento de variables allí:

    if user = someVariable { // do your stuff }

  2. moldes forzados (abajo):

    let myRectangle = someShape as! Rectangle

    Aquí, al forzar el lanzamiento, le dice al compilador que ya no se preocupe, ya que siempre tendrá una instancia de Rectangle allí. Y mientras eso se mantenga, no tiene que preocuparse. Los problemas comienzan cuando usted o sus colegas del proyecto comienzan a circular valores no rectangulares.

    ¿Solución? Utilice el enlace opcional (también conocido como if-let), realice el procesamiento de variables allí:

    if let myRectangle = someShape as? Rectangle { // yay, I have a rectangle }

  3. Opciones implícitamente sin envolver. Supongamos que tiene la siguiente definición de clase:

    class User { var name: String! init() { name = "(unnamed)" } func nicerName() { return "Mr/Ms " + name } }

    Ahora, si nadie se equivoca con la propiedad de name configurándola como nil , entonces funciona como se esperaba, sin embargo, si el User se inicializa desde un JSON que carece de la clave de name , entonces obtiene el error fatal al intentar usar la propiedad .

    ¿Solución? No los use :) A menos que esté 102% seguro de que la propiedad siempre tendrá un valor no nulo para el momento en que deba usarse. En la mayoría de los casos, la conversión a opcional o no opcional funcionará. Hacerlo no opcional también dará como resultado que el compilador lo ayude diciéndole las rutas de código que omitió dando un valor a esa propiedad

  4. Tomas de corriente no conectadas o todavía no conectadas. Este es un caso particular del escenario # 3. Básicamente tiene alguna clase cargada con XIB que desea usar.

    class SignInViewController: UIViewController { @IBOutlet var emailTextField: UITextField! }

    Ahora, si no conectó la salida desde el editor XIB, la aplicación se bloqueará tan pronto como quiera usar la salida. ¿Solución? Asegúrese de que todos los enchufes estén conectados. O usar el ? operador en ellos: emailTextField?.text = "[email protected]" . O declare la salida como opcional, aunque en este caso el compilador lo obligará a desenvolverlo en todo el código.

  5. Valores provenientes de Objective-C, y que no tienen anotaciones de nulabilidad. Supongamos que tenemos la siguiente clase Objective-C:

    @interface MyUser: NSObject @property NSString *name; @end

    Ahora, si no se especifican anotaciones de nulabilidad (ya sea explícitamente o mediante NS_ASSUME_NONNULL_BEGIN / NS_ASSUME_NONNULL_END ), ¡la propiedad del name se importará en Swift as String! (un IUO - opcional sin envolver implícitamente). Tan pronto como un código rápido quiera usar el valor, se bloqueará si el name es nulo.

    ¿Solución? Agregue anotaciones de nulabilidad a su código Objective-C. Sin embargo, tenga en cuenta que el compilador Objective-C es un poco permisivo en lo que respecta a la anulabilidad, puede terminar con valores nulos, incluso si los marcó explícitamente como no nonnull .


Dado que las respuestas anteriores explican claramente cómo jugar de forma segura con Opcionales. Trataré de explicar qué opciones son realmente rápidas.

Otra forma de declarar una variable opcional es

var i : Optional<Int>

Y el tipo opcional no es más que una enumeración con dos casos, es decir

enum Optional<Wrapped> : ExpressibleByNilLiteral { case none case some(Wrapped) . . . }

Entonces, para asignar un nulo a nuestra variable ''i''. Podemos hacer var i = Optional<Int>.none o para asignar un valor, pasaremos algún valor var i = Optional<Int>.some(28)

Según swift, ''nulo'' es la ausencia de valor. Y para crear una instancia inicializada con nil Tenemos que cumplir con un protocolo llamado ExpressibleByNilLiteral y excelente si lo adivinó, solo los Optionals ajustan a ExpressibleByNilLiteral y se desaconseja la conformidad con otros tipos.

ExpressibleByNilLiteral tiene un único método llamado init(nilLiteral:) que inicializa una instancia con nil. Por lo general, no llamará a este método y, según la documentación rápida, se desaconseja llamar a este inicializador directamente, ya que el compilador lo llama cada vez que inicializa un tipo Opcional con literal nil .

Incluso yo mismo tengo que envolver (sin juego de palabras) mi cabeza. Opcionales: D Happy Swfting All .


Esta pregunta surge TODO EL TIEMPO en SO. Es una de las primeras cosas con las que luchan los nuevos desarrolladores de Swift.

Fondo:

Swift utiliza el concepto de "Opcionales" para tratar con valores que pueden contener un valor, o no. En otros lenguajes como C, puede almacenar un valor de 0 en una variable para indicar que no contiene ningún valor. Sin embargo, ¿qué pasa si 0 es un valor válido? Entonces podrías usar -1. ¿Qué pasa si -1 es un valor válido? Y así.

Las opciones rápidas le permiten configurar una variable de cualquier tipo para contener un valor válido o ningún valor.

Pones un signo de interrogación después del tipo cuando declaras que una variable significa (tipo x, o ningún valor).

Un opcional es en realidad un contenedor que contiene una variable de un tipo dado o nada.

Una opción debe ser "desenvuelta" para obtener el valor dentro.

Los "!" El operador es un operador de "desenvolvimiento forzado". Dice "confía en mí. Sé lo que estoy haciendo. Te garantizo que cuando se ejecute este código, la variable no contendrá nada". Si te equivocas, te estrellas.

A menos que realmente sepa lo que está haciendo, evite el "!" forzar al operador de desenvolver. Es probablemente la mayor fuente de accidentes para los programadores principiantes de Swift.

Cómo lidiar con las opciones:

Hay muchas otras formas de tratar con opciones que son más seguras. Aquí hay algunos (no una lista exhaustiva)

Puede usar "enlace opcional" o "if let" para decir "si este opcional contiene un valor, guarde ese valor en una nueva variable no opcional. Si el opcional no contiene un valor, omita el cuerpo de esta instrucción if ".

Aquí hay un ejemplo de enlace opcional con nuestro foo opcional:

if let newFoo = foo //If let is called optional binding. { print("foo is not nil") } else { print("foo is nil") }

Tenga en cuenta que la variable que define cuando utiliza la opción de oferta solo existe (solo está "dentro del alcance") en el cuerpo de la instrucción if.

Alternativamente, puede usar una declaración de protección, que le permite salir de su función si la variable es nula:

func aFunc(foo: Int?) { guard let newFoo = input else { return } //For the rest of the function newFoo is a non-optional var }

Las declaraciones de Guardia se agregaron en Swift 2. Guard le permite preservar el "camino dorado" a través de su código y evitar niveles cada vez mayores de ifs anidados que a veces resultan del uso del enlace opcional "if let".

También hay una construcción llamada "operador de fusión nula". Toma la forma "optional_var ?? replace_val". Devuelve una variable no opcional con el mismo tipo que los datos contenidos en el opcional. Si el opcional contiene nil, devuelve el valor de la expresión después de "??" símbolo.

Entonces podrías usar un código como este:

let newFoo = foo ?? "nil" // "??" is the nil coalescing operator print("foo = /(newFoo)")

También puede usar el manejo de errores try / catch o guard, pero generalmente una de las otras técnicas anteriores es más limpia.

EDITAR:

Otro gotcha un poco más sutil con opcionales son los "opcionales implícitamente sin envolver. Cuando declaramos foo, podríamos decir:

var foo: String!

En ese caso, foo sigue siendo opcional, pero no tiene que desenvolverlo para referenciarlo. Eso significa que cada vez que intentas hacer referencia a foo, te cuelgas si es nulo.

Entonces este código:

var foo: String! let upperFoo = foo.capitalizedString

Se bloqueará en referencia a la propiedad CapitalizedString de foo a pesar de que no estamos desenvolviendo forzosamente a foo. la impresión se ve bien, pero no lo es.

Por lo tanto, debe tener mucho cuidado con las opciones implícitamente sin envolver. (y tal vez incluso evitarlos por completo hasta que tenga una sólida comprensión de las opciones).

En pocas palabras: cuando esté aprendiendo Swift por primera vez, simule el "!" El carácter no es parte del lenguaje. Es probable que te meta en problemas.


Este es un comentario más importante y por eso las opciones implícitamente desenvueltas pueden ser engañosas cuando se trata de depurar valores nil .

Piense en el siguiente código: Se compila sin errores / advertencias:

c1.address.city = c3.address.city

Sin embargo, en tiempo de ejecución da el siguiente error: Error fatal: se encontró inesperadamente nulo al desenvolver un valor opcional

¿Me puede decir qué objeto es nil ?

No puedes!

El código completo sería:

class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var c1 = NormalContact() let c3 = BadContact() c1.address.city = c3.address.city // compiler hides the truth from you and then you sudden get a crash } } struct NormalContact { var address : Address = Address(city: "defaultCity") } struct BadContact { var address : Address! } struct Address { var city : String }

Larga historia corta usando la var address : Address! estás ocultando la posibilidad de que una variable pueda ser nil de otros lectores. Y cuando se bloquea, dices "¡¿Qué demonios ?! ¡Mi address no es opcional, así que, ¿por qué me estrello ?!

Por lo tanto, es mejor escribir como tal:

c1.address.city = c2.address!.city // ERROR: Fatal error: Unexpectedly found nil while unwrapping an Optional value

¿Puedes decirme qué objeto es que fue nil ?

Esta vez, el código se te ha dejado más claro. Puede racionalizar y pensar que es probable que sea el parámetro de address que se desenvolvió con fuerza.

El código completo sería:

class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() var c1 = NormalContact() let c2 = GoodContact() c1.address.city = c2.address!.city c1.address.city = c2.address?.city // not compile-able. No deceiving by the compiler c1.address.city = c2.address.city // not compile-able. No deceiving by the compiler if let city = c2.address?.city { // safest approach. But that''s not what I''m talking about here. c1.address.city = city } } } struct NormalContact { var address : Address = Address(city: "defaultCity") } struct GoodContact { var address : Address? } struct Address { var city : String }


Los errores EXC_BAD_INSTRUCTION y fatal error: unexpectedly found nil while unwrapping an Optional value aparece más cuando se declara un @IBOutlet , pero no está conectado al guión gráfico .

También debe aprender sobre cómo funcionan los opcionales , mencionados en otras respuestas, pero esta es la única vez que me parece más importante.


Primero, debe saber qué es un valor opcional. Puede pasar al Lanzamiento de programación rápido

para detalles

En segundo lugar, debe saber que el valor opcional tiene dos estados. Uno es el valor completo, y el otro es el valor nulo. Entonces, antes de implementar un valor opcional, debe verificar qué estado es.

Puede usar if let ... o guard let ... else y así sucesivamente.

Otra forma, si no desea verificar su estado antes de su implementación, también puede usar var buildingName = buildingName ?? "buildingName" var buildingName = buildingName ?? "buildingName" lugar.


Tuve este error una vez cuando intentaba establecer mis valores de Outlets desde el método de preparación para segue de la siguiente manera:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let destination = segue.destination as? DestinationVC{ if let item = sender as? DataItem{ // This line pops up the error destination.nameLabel.text = item.name } } }

Luego descubrí que no puedo establecer los valores de las salidas del controlador de destino porque el controlador aún no se ha cargado o inicializado.

Entonces lo resolví de esta manera:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let destination = segue.destination as? DestinationVC{ if let item = sender as? DataItem{ // Created this method in the destination Controller to update its outlets after it''s being initialized and loaded destination.updateView(itemData: item) } } }

Controlador de destino:

// This variable to hold the data received to update the Label text after the VIEW DID LOAD var name = "" // Outlets @IBOutlet weak var nameLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. nameLabel.text = name } func updateView(itemDate: ObjectModel) { name = itemDate.name }

Espero que esta respuesta ayude a cualquiera con el mismo problema, ya que encontré que la respuesta marcada es un gran recurso para comprender las opciones y cómo funcionan, pero no ha abordado el problema directamente.


Swift 5 y superior ( opcional y encadenamiento opcional )

class Address { var buildingName: String? var buildingNumber: String? var street: String? func buildingIdentifier() -> String? { if let buildingNumber = buildingNumber, let street = street { return "/(buildingNumber) /(street)" } else if buildingName != nil { return buildingName } else { return nil } } }


Esta respuesta es wiki comunitaria . Si crees que podría mejorarse, ¡puedes edit !

Antecedentes: ¿Qué es un opcional?

En Swift, Optional es un tipo genérico que puede contener un valor (de cualquier tipo), o ningún valor en absoluto.

En muchos otros lenguajes de programación, a menudo se usa un valor "centinela" particular para indicar la falta de un valor . En Objective-C, por ejemplo, nil (el puntero nulo ) indica la falta de un objeto. Pero esto se vuelve más complicado cuando se trabaja con tipos primitivos: ¿debería usarse -1 para indicar la ausencia de un número entero, o tal vez INT_MIN , o algún otro número entero? Si se elige cualquier valor particular para que signifique "sin número entero", eso significa que ya no puede tratarse como un valor válido .

Swift es un lenguaje de tipo seguro, lo que significa que el lenguaje le ayuda a ser claro acerca de los tipos de valores con los que puede trabajar su código. Si parte de su código espera una Cadena, el tipo de seguridad le impide pasar un Int por error.

En Swift, cualquier tipo puede hacerse opcional . Un valor opcional puede tomar cualquier valor del tipo original or el valor especial nil .

Los opcionales se definen con un ? sufijo en el tipo:

var anInt: Int = 42 var anOptionalInt: Int? = 42 var anotherOptionalInt: Int? // `nil` is the default when no value is provided

La falta de un valor en un opcional se indica por nil :

anOptionalInt = nil

(Tenga en cuenta que este valor nil no es igual al nil en Objective-C. En Objective-C, nil es la ausencia de un puntero de objeto válido; en Swift, los opcionales no están restringidos a objetos / tipos de referencia. Opcional se comporta de manera similar a Haskell Maybe )

¿Por qué recibí " error fatal: inesperadamente encontrado nulo al desenvolver un valor opcional "?

Para acceder al valor de un opcional (si tiene uno), debe desenvolverlo . Un valor opcional se puede desenvolver de forma segura o forzada. Si desenvuelve a la fuerza un opcional, y no tenía un valor, su programa se bloqueará con el mensaje anterior.

Xcode le mostrará el bloqueo resaltando una línea de código. El problema ocurre en esta línea.

Este bloqueo puede ocurrir con dos tipos diferentes de desenrollado forzado:

1. Desenvolvimiento de fuerza explícito

Esto se hace con el ! operador de forma opcional. Por ejemplo:

let anOptionalString: String? print(anOptionalString!) // <- CRASH

Como anOptionalString es nil aquí, obtendrá un bloqueo en la línea donde fuerza desenvolverlo.

2. Opciones opcionales implícitamente sin envolver

Estos se definen con un ! , en lugar de un ? después del tipo.

var optionalDouble: Double! // this value is implicitly unwrapped wherever it''s used

Se supone que estos opcionales contienen un valor. Por lo tanto, siempre que acceda a una opción sin envoltura implícita, automáticamente se desenvolverá forzosamente para usted. Si no contiene un valor, se bloqueará.

print(optionalDouble) // <- CRASH

Para determinar qué variable causó el bloqueo, puede mantener presionada mientras hace clic para mostrar la definición, donde puede encontrar el tipo opcional.

Los IBOutlets, en particular, generalmente son opciones implícitas sin envolver. Esto se debe a que su xib o storyboard vincularán las salidas en tiempo de ejecución, después de la inicialización. Por lo tanto, debe asegurarse de que no está accediendo a las salidas antes de que se carguen. También debe verificar que las conexiones sean correctas en su archivo storyboard / xib, de lo contrario, los valores serán nil en el tiempo de ejecución y, por lo tanto, se bloquearán cuando estén implícitamente sin envolver Al arreglar las conexiones, intente eliminar las líneas de código que definen sus puntos de venta, luego vuelva a conectarlos.

¿Cuándo debería forzar el desenvolvimiento de un Opcional?

Desenvolvimiento de fuerza explícito

Como regla general, nunca debe forzar explícitamente el desenvolvimiento de un opcional con el ! operador. ¡Puede haber casos en donde usar ! es aceptable, pero solo debería usarlo si está 100% seguro de que lo opcional contiene un valor.

Si bien puede haber una ocasión en la que pueda usar el desenvolvimiento forzado, como sabe con certeza que un opcional contiene un valor, no hay un solo lugar donde no pueda desenvolver ese opcional de manera segura.

Opciones implícitas sin envolver

Estas variables están diseñadas para que pueda diferir su asignación hasta más adelante en su código. Es su responsabilidad asegurarse de que tengan un valor antes de acceder a ellos. Sin embargo, debido a que implican el desenvolvimiento forzado, siguen siendo inherentemente inseguros, ya que suponen que su valor no es nulo, a pesar de que la asignación nula es válida.

Solo debe usar opciones opcionales implícitamente sin envolver como último recurso . Si puede utilizar una variable diferida o proporcionar un valor predeterminado para una variable, debe hacerlo en lugar de utilizar una opción implícita sin envolver.

Sin embargo, hay algunos escenarios en los que las opciones opcionales sin envoltura son beneficiosas , y aún puede usar varias formas de desenvolverlas de manera segura como se enumera a continuación, pero siempre debe usarlas con la debida precaución.

¿Cómo puedo tratar con seguridad los opcionales?

La forma más sencilla de verificar si un opcional contiene un valor, es compararlo con nil .

if anOptionalInt != nil { print("Contains a value!") } else { print("Doesn’t contain a value.") }

Sin embargo, el 99.9% del tiempo cuando trabaje con opciones, en realidad querrá acceder al valor que contiene, si es que contiene uno. Para hacer esto, puede usar Enlace opcional .

Enlace opcional

El enlace opcional le permite verificar si un opcional contiene un valor, y le permite asignar el valor sin envolver a una nueva variable o constante. Utiliza la sintaxis if let x = anOptional {...} o if var x = anOptional {...} , dependiendo de si necesita modificar el valor de la nueva variable después de vincularla.

Por ejemplo:

if let number = anOptionalInt { print("Contains a value! It is /(number)!") } else { print("Doesn’t contain a number") }

Lo que esto hace es comprobar primero que el opcional contiene un valor. Si lo hace , el valor ''sin envolver'' se asigna a una nueva variable ( number ), que puede usar libremente como si no fuera opcional. Si el opcional no contiene un valor, se invocará la cláusula else, como era de esperar.

Lo bueno de la encuadernación opcional es que puede desenvolver múltiples opcionales al mismo tiempo. Simplemente puede separar las declaraciones con una coma. La declaración tendrá éxito si todas las opciones se desenvolvieran.

var anOptionalInt : Int? var anOptionalString : String? if let number = anOptionalInt, let text = anOptionalString { print("anOptionalInt contains a value: /(number). And so does anOptionalString, it’s: /(text)") } else { print("One or more of the optionals don’t contain a value") }

Otro buen truco es que también puede usar comas para verificar una determinada condición en el valor, después de desenvolverlo.

if let number = anOptionalInt, number > 0 { print("anOptionalInt contains a value: /(number), and it’s greater than zero!") }

El único inconveniente con el uso del enlace opcional dentro de una declaración if es que solo puede acceder al valor sin envolver dentro del alcance de la declaración. Si necesita acceder al valor desde fuera del alcance de la declaración, puede usar una declaración de protección .

Una declaración de protección le permite definir una condición para el éxito, y el alcance actual solo continuará ejecutándose si se cumple esa condición. Se definen con la guard condition else {...} sintaxis guard condition else {...} .

Entonces, para usarlos con un enlace opcional, puede hacer esto:

guard let number = anOptionalInt else { return }

(Tenga en cuenta que dentro del cuerpo de guardia, debe usar una de las declaraciones de transferencia de control para salir del alcance del código que se está ejecutando actualmente).

Si anOptionalInt contiene un valor, se anOptionalInt y se asignará a la nueva constante de number . El código después del guardia continuará ejecutándose. Si no contiene un valor, el guardia ejecutará el código entre paréntesis, lo que conducirá a la transferencia de control, de modo que el código inmediatamente posterior no se ejecutará.

Lo realmente bueno de las declaraciones de guardia es que el valor sin envolver ahora está disponible para usar en el código que sigue a la declaración (ya que sabemos que el código futuro solo puede ejecutarse si el opcional tiene un valor). Esto es ideal para eliminar las ''pirámides de la fatalidad'' creadas al anidar múltiples sentencias if.

Por ejemplo:

guard let number = anOptionalInt else { return } print("anOptionalInt contains a value, and it’s: /(number)!")

Los guardias también admiten los mismos trucos que la declaración if admite, como desenvolver múltiples opciones al mismo tiempo y usar la cláusula where .

Si usa una declaración if o guard depende completamente de si algún código futuro requiere que lo opcional contenga un valor.

Operador de fusión nula

El Operador de fusión nula es una ingeniosa versión abreviada del operador condicional ternario , diseñado principalmente para convertir opcionales en no opcionales. Tiene la sintaxis a ?? b a ?? b , donde a es un tipo opcional b es el mismo tipo que a (aunque generalmente no es opcional).

Esencialmente le permite decir "Si a contiene un valor, desenvuélvalo. Si no es así, devuelve b lugar ". Por ejemplo, podría usarlo así:

let number = anOptionalInt ?? 0

Esto definirá una constante de number de tipo Int , que contendrá el valor de anOptionalInt , si contiene un valor, o 0 caso contrario.

Es solo una abreviatura de:

let number = anOptionalInt != nil ? anOptionalInt! : 0

Encadenamiento opcional

Puede usar el encadenamiento opcional para llamar a un método o acceder a una propiedad en un opcional. Esto se hace simplemente sufijando el nombre de la variable con un ? cuando lo usa

Por ejemplo, supongamos que tenemos una variable foo , de tipo una instancia opcional de Foo .

var foo : Foo?

Si quisiéramos llamar a un método en foo que no devuelve nada, simplemente podemos hacer:

foo?.doSomethingInteresting()

Si foo contiene un valor, se llamará a este método. Si no es así, no pasará nada malo: el código simplemente continuará ejecutándose.

(Este es un comportamiento similar al envío de mensajes a nil en Objective-C)

Por lo tanto, esto también se puede utilizar para establecer propiedades y métodos de llamada. Por ejemplo:

foo?.bar = Bar()

Nuevamente, nada malo sucederá aquí si foo es nil . Su código simplemente continuará ejecutándose.

Otro buen truco que el encadenamiento opcional le permite hacer es verificar si establecer una propiedad o llamar a un método fue exitoso. Puede hacer esto comparando el valor de retorno a nil .

(Esto se debe a que un valor opcional devolverá Void? lugar de Void en un método que no devuelve nada)

Por ejemplo:

if (foo?.bar = Bar()) != nil { print("bar was set successfully") } else { print("bar wasn’t set successfully") }

Sin embargo, las cosas se vuelven un poco más difíciles cuando se trata de acceder a propiedades o métodos de llamada que devuelven un valor. Debido a que foo es opcional, todo lo que devuelva también será opcional. Para lidiar con esto, puede desenvolver los opcionales que se devuelven utilizando uno de los métodos anteriores, o desenvolverlos antes de acceder a los métodos o llamar a los métodos que devuelven valores.

Además, como su nombre lo indica, puede ''encadenar'' estas declaraciones juntas. Esto significa que si foo tiene una propiedad opcional baz , que tiene una propiedad qux , puede escribir lo siguiente:

let optionalQux = foo?.baz?.qux

Nuevamente, debido a que foo y baz son opcionales, el valor devuelto por qux siempre será opcional, independientemente de si qux es opcional.

map y flatMap

Una característica a menudo infrautilizada con opciones es la capacidad de usar las funciones map y flatMap . Estos le permiten aplicar transformaciones no opcionales a variables opcionales. Si un opcional tiene un valor, puede aplicarle una transformación determinada. Si no tiene un valor, permanecerá nil .

Por ejemplo, supongamos que tiene una cadena opcional:

let anOptionalString:String?

Al aplicarle la función de map , podemos usar la función stringByAppendingString para concatenarla a otra cadena.

Debido a que stringByAppendingString toma un argumento de cadena no opcional, no podemos ingresar nuestra cadena opcional directamente. Sin embargo, al usar map , podemos usar allow stringByAppendingString para usar si anOptionalString tiene un valor.

Por ejemplo:

var anOptionalString:String? = "bar" anOptionalString = anOptionalString.map {unwrappedString in return "foo".stringByAppendingString(unwrappedString) } print(anOptionalString) // Optional("foobar")

Sin embargo, si anOptionalString no tiene un valor, map devolverá nil . Por ejemplo:

var anOptionalString:String? anOptionalString = anOptionalString.map {unwrappedString in return "foo".stringByAppendingString(unwrappedString) } print(anOptionalString) // nil

flatMap funciona de manera similar al map , excepto que le permite devolver otro opcional desde el cuerpo del cierre. Esto significa que puede ingresar un opcional en un proceso que requiere una entrada no opcional, pero puede generar un opcional en sí mismo.

try!

El sistema de manejo de errores de Swift se puede usar de manera segura con Do-Try-Catch :

do { let result = try someThrowingFunc() } catch { print(error) }

Si someThrowingFunc() arroja un error, el error se capturará de forma segura en el bloque catch .

La constante de error que ve en el bloque catch no ha sido declarada por nosotros, se genera automáticamente por catch .

También puede declarar el error usted mismo, tiene la ventaja de poder transmitirlo a un formato útil, por ejemplo:

do { let result = try someThrowingFunc() } catch let error as NSError { print(error.debugDescription) }

Usar try esta manera es la forma correcta de probar, capturar y manejar errores provenientes de funciones de lanzamiento.

También hay try? que absorbe el error:

if let result = try? someThrowingFunc() { // cool } else { // handle the failure, but there''s no error information available }

¡Pero el sistema de manejo de errores de Swift también proporciona una forma de "forzar el intento" con el try! :

let result = try! someThrowingFunc()

Los conceptos explicados en esta publicación también se aplican aquí: si se produce un error, la aplicación se bloqueará.

¡Solo debes usar try! si puede probar que su resultado nunca fallará en su contexto, y esto es muy raro.

La mayoría de las veces usará el sistema completo Do-Try-Catch, y el opcional, try? , en los raros casos en los que manejar el error no es importante.

Recursos