Buscar..


Introducción

“Un valor opcional contiene un valor o contiene cero para indicar que falta un valor”

Extracto de: Apple Inc. "El lenguaje de programación Swift (Swift 3.1 Edition)." IBooks. https://itun.es/us/k5SW7.l

Los casos de uso opcionales básicos incluyen: para una constante (let), el uso de un opcional dentro de un loop (if-let), desenvolver de forma segura un valor opcional dentro de un método (guarda-let), y como parte de los bucles de switch (case-let ), por defecto a un valor si es nulo, usando el operador de fusión (??)

Sintaxis

  • var optionalName: optionalType? // declara un tipo opcional, por defecto es nil
  • var optionalName: optionalType? = valor // declara un opcional con un valor
  • var optionalName: optionalType! // declara un opcional implícitamente sin envolver
  • ¡Opcional! // forzar desenvolver un opcional

Observaciones

Para obtener más información sobre las opciones, consulte El lenguaje de programación Swift .

Tipos de opcionales

Los opcionales son un tipo de enumeración genérico que actúa como un contenedor. Esta envoltura permite que una variable tenga uno de dos estados: el valor del tipo definido por el usuario o nil , que representa la ausencia de un valor.

Esta habilidad es particularmente importante en Swift porque uno de los objetivos de diseño establecidos del lenguaje es trabajar bien con los marcos de Apple. Muchos (la mayoría) de los marcos de trabajo de Apple utilizan nil debido a su facilidad de uso y su importancia para los patrones de programación y el diseño de API en Objective-C.

En Swift, para que una variable tenga un valor nil , debe ser opcional. Se pueden crear opcionales agregando una ! o un ? al tipo de variable. Por ejemplo, para hacer un Int opcional, puedes usar

var numberOne: Int! = nil
var numberTwo: Int? = nil

? los opcionales deben ser explícitamente desenvueltos y deben usarse si no está seguro de si la variable tendrá un valor cuando acceda a ella. Por ejemplo, al convertir una cadena en un Int , el resultado es un Int? opcional Int? , porque se devolverá nil si la cadena no es un número válido

let str1 = "42"
let num1: Int? = Int(str1) // 42

let str2 = "Hello, World!"
let num2: Int? = Int(str2) // nil

! los opcionales se desenvuelven automáticamente y solo deben usarse cuando esté seguro de que la variable tendrá un valor cuando acceda a ella. Por ejemplo, un UIButton! global UIButton! variable que se inicializa en viewDidLoad()

//myButton will not be accessed until viewDidLoad is called,
//so a ! optional can be used here
var myButton: UIButton!

override func viewDidLoad(){
    self.myButton = UIButton(frame: self.view.frame)
    self.myButton.backgroundColor = UIColor.redColor()
    self.view.addSubview(self.myButton)
}

Desenvolviendo un opcional

Para poder acceder al valor de un opcional, se debe desempaquetar.

Condicionalmente, puede desenvolver un Opcional usando el enlace opcional y forzar el desenvolver un Opcional usando el ! operador.

El desenvolver condicionalmente pregunta "¿Tiene esta variable un valor?" mientras que la fuerza de desenvolvimiento dice "Esta variable tiene un valor".

Si obliga a desenvolver una variable que es nil , su programa arrojará un nulo encontrado inesperadamente mientras desenvuelve una excepción y falla opcionales , por lo que debe considerar cuidadosamente si lo usa ! es apropiado.

var text: String? = nil
var unwrapped: String = text! //crashes with "unexpectedly found nil while unwrapping an Optional value"

Para un desenvolvimiento seguro, puede usar una sentencia if-let , que no arrojará una excepción o bloqueo si el valor envuelto es nil :

var number: Int?
if let unwrappedNumber = number {       // Has `number` been assigned a value?
    print("number: \(unwrappedNumber)") // Will not enter this line
} else {
    print("number was not assigned a value")
}

O, una declaración de guardia :

var number: Int?
guard let unwrappedNumber = number else {
    return
}
print("number: \(unwrappedNumber)")

Tenga en cuenta que el alcance de la variable unwrappedNumber está dentro de la sentencia if-let y fuera del bloque de guard .

Puede encadenar el desenvolvimiento de muchos opcionales, esto es principalmente útil en los casos en que su código requiere más de una variable para ejecutarse correctamente:

var firstName:String?
var lastName:String?

if let fn = firstName, let ln = lastName {
    print("\(fn) + \(ln)")//pay attention that the condition will be true only if both optionals are not nil.
}

Tenga en cuenta que todas las variables deben ser desenvueltas para pasar la prueba con éxito, de lo contrario no tendría forma de determinar qué variables se desenvolvieron y cuáles no.

Puede encadenar declaraciones condicionales usando sus opcionales inmediatamente después de que se desenvuelva. Esto significa que no hay instrucciones anidadas si - si no!

var firstName:String? = "Bob"
var myBool:Bool? = false

if let fn = firstName, fn == "Bob", let bool = myBool, !bool {
    print("firstName is bob and myBool was false!")
}

Operador Coalescente Nil

Puede utilizar el operador de unión nula para desenvolver un valor si no es nulo, de lo contrario, proporcione un valor diferente:

func fallbackIfNil(str: String?) -> String {
    return str ?? "Fallback String"
}
print(fallbackIfNil("Hi")) // Prints "Hi"
print(fallbackIfNil(nil)) // Prints "Fallback String"

Este operador puede hacer un cortocircuito , lo que significa que si el operando de la izquierda no es nulo, el operando de la derecha no se evaluará:

func someExpensiveComputation() -> String { ... }

var foo : String? = "a string"
let str = foo ?? someExpensiveComputation()

En este ejemplo, como foo no es nulo, no se llamará a someExpensiveComputation() .

También puede encadenar varias declaraciones coalescentes nulas juntas:

var foo : String?
var bar : String?

let baz = foo ?? bar ?? "fallback string"

En este ejemplo, a baz se le asignará el valor no envuelto de foo si no es nulo, de lo contrario se le asignará el valor desenvuelto de la bar si no es nil, de lo contrario se le asignará el valor de reserva.

Encadenamiento opcional

Puede usar el encadenamiento opcional para llamar a un método , acceder a una propiedad o subíndice como opcional. Esto se hace colocando un ? entre la variable opcional dada y el miembro dado (método, propiedad o subíndice).

struct Foo {
    func doSomething() {
        print("Hello World!")
    }
}

var foo : Foo? = Foo()

foo?.doSomething() // prints "Hello World!" as foo is non-nil

Si foo contiene un valor, se doSomething() . Si foo es nil , entonces no ocurrirá nada malo: el código simplemente fallará en silencio y continuará ejecutándose.

var foo : Foo? = nil

foo?.doSomething() // will not be called as foo is nil

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

La razón por la que el encadenamiento opcional se nombra como tal es porque la "opcionalidad" se propagará a través de los miembros a los que llama / accede. Lo que esto significa es que los valores de retorno de cualquier miembro utilizado con el encadenamiento opcional serán opcionales, independientemente de si están escritos como opcionales o no.

struct Foo {
    var bar : Int
    func doSomething() { ... }
}

let foo : Foo? = Foo(bar: 5)
print(foo?.bar) // Optional(5)

Aquí foo?.bar está devolviendo un Int? aunque la bar no es opcional, como foo sí es opcional.

A medida que se propaga la opcionalidad, los métodos que devuelven Void se devolverán Void? cuando se llama con el encadenamiento opcional. Esto puede ser útil para determinar si el método fue llamado o no (y por lo tanto si el opcional tiene un valor).

let foo : Foo? = Foo()

if foo?.doSomething() != nil {
    print("foo is non-nil, and doSomething() was called")
} else {
    print("foo is nil, therefore doSomething() wasn't called")
}

Aquí estamos comparando el Void? devuelva el valor con nil para determinar si se llamó al método (y, por lo tanto, si foo no es nulo).

Descripción general - ¿Por qué Optionals?

A menudo, cuando se programa, es necesario hacer una distinción entre una variable que tiene un valor y otra que no. Para tipos de referencia, como los punteros C, se puede usar un valor especial como null para indicar que la variable no tiene valor. Para los tipos intrínsecos, como un entero, es más difícil. Se puede usar un valor nominado, como -1, pero esto se basa en la interpretación del valor. También elimina ese valor "especial" del uso normal.

Para solucionar esto, Swift permite que cualquier variable se declare como opcional. Esto está indicado por el uso de un? o! después del tipo (ver Tipos de opcionales )

Por ejemplo,

var possiblyInt: Int?

declara una variable que puede o no contener un valor entero.

El valor especial nil indica que actualmente no hay ningún valor asignado a esta variable.

possiblyInt = 5      // PossiblyInt is now 5
possiblyInt = nil    // PossiblyInt is now unassigned

nil también se puede utilizar para probar un valor asignado:

if possiblyInt != nil {
    print("possiblyInt has the value \(possiblyInt!)")
}

Tenga en cuenta el uso de ! en la declaración de impresión para desenvolver el valor opcional.

Como ejemplo de un uso común de los opcionales, considere una función que devuelve un entero de una cadena que contiene dígitos; Es posible que la cadena contenga caracteres sin dígitos, o incluso que esté vacía.

¿Cómo puede una función que devuelve un simple Int indicar un error? No puede hacerlo devolviendo un valor específico ya que esto evitaría que ese valor se analice desde la cadena.

var someInt
someInt = parseInt("not an integer") // How would this function indicate failure?

En Swift, sin embargo, esa función puede simplemente devolver un Int opcional . Entonces el fallo es indicado por el valor de retorno de nil .

var someInt?
someInt = parseInt("not an integer")  // This function returns nil if parsing fails
if someInt == nil {
    print("That isn't a valid integer")
}


Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow