¿Qué significa "desenvolver la instancia"? ¿Por qué es necesario?
Hasta donde puedo hacer ejercicio (esto también es muy nuevo para mí) ...
El término "envuelto" implica que debemos pensar en una variable Opcional como un regalo, envuelto en papel brillante, que podría (¡lamentablemente!) Estar vacío .
Cuando se "ajusta", el valor de una variable opcional es una enumeración con dos valores posibles (un poco como un booleano). Esta enumeración describe si la variable tiene un valor ( Some(T)
) o no ( None
).
Si hay un valor, esto puede obtenerse "desenvolviendo" la variable (obteniendo el T
de Some(T)
).
¿Cómo es john!.apartment = number73
diferente de john.apartment = number73
? (Parafraseado)
Si escribe el nombre de una variable Opcional (por ejemplo john
, texto , sin el !
), esto se refiere a la enumeración "envuelta" (Algunos / Ninguno), no al valor en sí (T). Entonces john
no es una instancia de Person
, y no tiene un apartment
miembro:
john.apartment
// 'Person?' does not have a member named 'apartment'
El Person
valor real se puede desenvolver de varias maneras:
- "desenvolvimiento forzado":
john!
(da el Person
valor si existe, error de tiempo de ejecución si es nulo)
- "enlace opcional":
if let p = john { println(p) }
(ejecuta println
el valor si existe)
- "encadenamiento opcional":
john?.learnAboutSwift()
(ejecuta este método inventado si el valor existe)
Supongo que eliges una de estas formas de desenvolver, dependiendo de lo que suceda en el caso nulo y de cuán probable sea. Este diseño de lenguaje obliga a que el caso nulo se maneje explícitamente, lo que supongo que mejora la seguridad sobre Obj-C (donde es fácil olvidar manejar el caso nulo).
Actualización :
El signo de exclamación también se usa en la sintaxis para declarar "Opciones implícitas sin envolver".
En los ejemplos hasta ahora, la john
variable ha sido declarada como var john:Person?
, y es una Opcional. Si desea el valor real de esa variable, debe desenvolverla, utilizando uno de los tres métodos anteriores.
Si se declarara como en su var john:Person!
lugar, la variable sería una Opcional implícitamente sin envolver (consulte la sección con este encabezado en el libro de Apple). No es necesario desenvolver este tipo de variable al acceder al valor, y john
puede usarse sin sintaxis adicional. Pero el libro de Apple dice:
Las opciones implícitamente desenvueltas no deben usarse cuando existe la posibilidad de que una variable se vuelva nula en un momento posterior. Utilice siempre un tipo opcional normal si necesita verificar un valor nulo durante la vida útil de una variable.
Actualización 2 :
El artículo " Características interesantes de Swift " de Mike Ash ofrece cierta motivación para los tipos opcionales. Creo que es genial, una escritura clara.
Actualización 3 :
Otro artículo útil sobre el uso opcional implícitamente sin envolver para el signo de exclamación: " Swift and the Last Mile " de Chris Adamson. El artículo explica que esta es una medida pragmática de Apple utilizada para declarar los tipos utilizados por sus marcos Objective-C que pueden contener nulo. Declarar un tipo como opcional (usando ?
) o implícitamente sin envolver (usando !
) es "una compensación entre seguridad y conveniencia". En los ejemplos dados en el artículo, Apple ha decidido declarar los tipos como implícitamente desenvueltos, haciendo que el código de llamada sea más conveniente, pero menos seguro.
Tal vez Apple podría revisar sus marcos en el futuro, eliminando la incertidumbre de los parámetros implícitamente desenvueltos ("probablemente nunca nulos") y reemplazándolos por opcionales ("ciertamente podría ser nulo en particular [¡con suerte, documentado!] Circunstancias") o no estándar -opcionales ("nunca es nulo"), basadas en el comportamiento exacto de su código Objective-C.
Esto es lo que creo que es la diferencia:
Significa que John puede ser nulo
El compilador interpretará esta línea como:
Mientras
El compilador interpretará esta línea simplemente:
Por lo tanto, usando! desenvolverá la instrucción if y hará que se ejecute más rápido, pero si john es nulo, se producirá un error de tiempo de ejecución.
Entonces, envolver aquí no significa que está envuelto en memoria, pero significa que está envuelto en código, en este caso está envuelto con una declaración if, y debido a que Apple presta mucha atención al rendimiento en tiempo de ejecución, quieren darle una forma de haga que su aplicación funcione con el mejor rendimiento posible.
Actualizar:
Volviendo a esta respuesta después de 4 años, ya que obtuve la mayor reputación en Stackoverflow :) No entendí un poco el significado de desenvolver en ese momento. Ahora, después de 4 años, creo que el significado de desenvolver aquí es expandir el código de su forma compacta original. También significa eliminar la vaguedad alrededor de ese objeto, ya que no estamos seguros por definición de que sea nulo o no. Al igual que la respuesta de Ashley anterior, piense en ello como un regalo que no podría contener nada. Pero sigo pensando que el desenvolvimiento es desenvolvimiento de código y no desenvolvimiento basado en memoria como el uso de la enumeración.
fuente
TL; DR
¿Qué significa un signo de exclamación en el lenguaje Swift?
Ejemplo
Fuente: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399
fuente
let f: String! = "hello"
y luegoprint(f)
, la salida es enOptional("hello")
lugar de solo"hello"
.Si juan fuera una var opcional (declarada así)
entonces sería posible que John no tuviera ningún valor (en el lenguaje de ObjC, valor nulo)
El signo de exclamación básicamente le dice al compilador "Sé que esto tiene un valor, no necesita probarlo". Si no desea utilizarlo, puede probarlo condicionalmente:
El interior de esto solo evaluará si John tiene un valor.
fuente
“let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.”
Pero funciona bien con no! Algo parece extraño aquí.John?
yJohn
son dos tipos diferentes. Uno es de tipo Persona opcional y el otro Tipo de persona. La persona opcional debe desenvolverse antes de que pueda sacar a la persona. Pero como usted dice, esto parece suceder al menos en estas circunstancias sin tener que hacer nada. Esto parece hacer el! redundante. A menos que el ! SIEMPRE es opcional, pero se sugiere hacer algo para detectar errores de tiempo de compilación. Algo así como asignar vars / lets a un tipo particular puede ser explícitolet John: Person = ...
pero también se puede inferirlet John = ...
.Alguna perspectiva general para agregar a las otras respuestas útiles pero más centradas en los detalles:
En Swift, el signo de exclamación aparece en varios contextos:
let name = nameLabel!.text
var logo: UIImageView!
logo.image = thing as! UIImage
try! NSJSONSerialization.JSONObjectWithData(data, [])
Cada uno de estos es una construcción de lenguaje diferente con un significado diferente, pero todos tienen tres cosas importantes en común:
1. Los signos de exclamación eluden los controles de seguridad en tiempo de compilación de Swift.
Cuando lo usa
!
en Swift, esencialmente dice: "Oye, compilador, sé que cree que podría ocurrir un error aquí, pero sé con total certeza que nunca lo hará".No todo el código válido cabe en la caja del sistema de tipos de tiempo de compilación de Swift, o la comprobación de tipos estáticos de cualquier idioma, para el caso. Hay situaciones en las que puede probar lógicamente que nunca se producirá un error, pero no puede probarlo al compilador . Es por eso que los diseñadores de Swift agregaron estas características en primer lugar.
Sin embargo, cada vez que usa
!
, descarta tener una ruta de recuperación para un error, lo que significa que ...2. Los puntos de exclamación son posibles accidentes.
Un signo de exclamación también dice: "Hola Swift, estoy tan seguro de que este error nunca puede ocurrir que es mejor que bloquees toda mi aplicación que codificar una ruta de recuperación para ella".
Esa es una afirmación peligrosa. Se puede ser la correcta: en clave de misión crítica en la que han pensado mucho sobre invariantes de su código, puede ser que la salida falsa es peor que un accidente.
Sin embargo, cuando veo
!
en la naturaleza, rara vez se usa con tanta atención. En cambio, con demasiada frecuencia significa, "este valor era opcional y realmente no pensé demasiado sobre por qué podría ser nulo o cómo manejar adecuadamente esa situación, pero agregarlo!
lo compiló ... así que mi código es correcto, ¿verdad?"Cuidado con la arrogancia del signo de exclamación. En lugar…
3. Los puntos de exclamación se usan mejor con moderación.
Cada una de estas
!
construcciones tiene una?
contraparte que te obliga a lidiar con el caso de error / nulo:if let name = nameLabel?.text { ... }
var logo: UIImageView?
logo.image = thing as? UIImage
try? NSJSONSerialization.JSONObjectWithData(data, [])
Si tiene la tentación de usar
!
, siempre es bueno considerar cuidadosamente por qué no lo está usando?
. ¿Bloquear su programa es realmente la mejor opción si la!
operación falla? ¿Por qué ese valor es opcional / no disponible?¿Existe una ruta de recuperación razonable que su código podría tomar en el caso de nulo / error? Si es así, codifíquelo.
Si no puede ser nulo, si el error nunca puede suceder, ¿hay alguna forma razonable de reelaborar su lógica para que el compilador lo sepa? Si es así, hazlo; su código será menos propenso a errores.
Hay momentos en que no hay una forma razonable de manejar un error, y simplemente ignorar el error, y así proceder con datos incorrectos, sería peor que estrellarse. Esos son los momentos para usar el desenvolvimiento forzado.
Periódicamente busco en toda mi base de código
!
y audito cada uso del mismo. Muy pocos usos resisten el escrutinio. (Al escribir estas líneas, todo el marco de Siesta tiene exactamente dos instancias de él).Eso no quiere decir que nunca debe usarlo
!
en su código, solo que debe usarlo conscientemente y nunca hacerlo la opción predeterminada.fuente
func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) }
Dado 3. ¿Hay una mejor manera de escribirlo?func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { guard let nonNilReceiptData = receiptData else { return false} return (hasValidTrial(nonNilReceiptData) || isNotExpired(nonNilReceiptData)) && isNotCancelled(nonNilReceiptData) }
john
Es opcionalvar
. Entonces puede ser contiene unnil
valor. Para asegurarse de que el valor no sea nulo, utilice un!
al final delvar
nombre.De la documentación
“Una vez que esté seguro de que el opcional contiene un valor, puede acceder a su valor subyacente agregando un signo de exclamación (!) Al final del nombre del opcional. El signo de exclamación efectivamente dice: “Sé que este opcional definitivamente tiene un valor; por favor úsalo ".
Otra forma de verificar el valor no nulo es
fuente
john.apartment = number73
también dice "Sé que este opcional definitivamente tiene un valor; utilícelo" ...Aquí hay unos ejemplos:
Donde
word
es un valor opcional. significa que puede o no contener un valor.Aquí
name
tiene un valor para que podamos asignarloDonde
dog
se desenvuelve con fuerza significa que debe contener un valorLa aplicación se bloqueará porque estamos asignados
nil
a desenvueltofuente
var c:Int = nil
obtendrá: "Cero no puede inicializar el tipo especificado 'int'"En este caso...
var John: Persona!
significa que, inicialmente, John tendrá un valor nulo, se establecerá y una vez que se establezca, nunca volverá a estar dirigido por nada. Por lo tanto, por conveniencia, puedo usar la sintaxis más fácil para acceder a una variable opcional porque esta es una "opción implícitamente desenvuelta"
fuente
Si ha venido de un lenguaje de familia C, estará pensando "puntero al objeto de tipo X, que podría ser la dirección de memoria 0 (NULL)", y si viene de un lenguaje de tipo dinámico, estará pensando "Objeto que probablemente sea de tipo X pero podría ser de tipo indefinido". Ninguno de estos es realmente correcto, aunque de manera indirecta, el primero está cerca.
La forma en que debería pensar es como si fuera un objeto como:
Cuando está probando su valor opcional con
foo == nil
realmente está regresandofoo.isNil
, y cuando dicefoo!
que está regresandofoo.realObject
con una afirmación de quefoo.isNil == false
. Es importante tener en cuenta esto porque si enfoo
realidad es nulo cuando lo hacesfoo!
, es un error de tiempo de ejecución, por lo que generalmente querría usar un let condicional en lugar de estar muy seguro de que el valor no será nulo. Este tipo de truco significa que el lenguaje puede ser fuertemente tipado sin obligarlo a probar si los valores son nulos en todas partes.En la práctica, realmente no se comporta así porque el compilador realiza el trabajo. En un nivel alto hay un tipo
Foo?
que es independiente deFoo
, y que evita que los funcs que aceptan el tipoFoo
reciban un valor nulo, pero en un nivel bajo un valor opcional no es un objeto verdadero porque no tiene propiedades ni métodos; es probable que, de hecho, sea un puntero que puede ser NULL (0) con la prueba adecuada cuando se desenrolla a la fuerza.Hay otra situación en la que verías un signo de exclamación en un tipo, como en:
Esto es más o menos equivalente a aceptar un opcional con un desenvolvimiento forzado, es decir:
Puede usar esto para tener un método que técnicamente acepta un valor opcional pero que tendrá un error de tiempo de ejecución si es nulo. En la versión actual de Swift, esto aparentemente pasa por alto la afirmación de no es nula, por lo que en su lugar tendrá un error de bajo nivel. Generalmente no es una buena idea, pero puede ser útil al convertir código de otro idioma.
fuente
Los ! significa que estás forzando a desenvolver el objeto! sigue. Se puede encontrar más información en la documentación de Apple, que se puede encontrar aquí: https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/TheBasics.html
fuente
Si está familiarizado con C #, esto es como los tipos anulables que también se declaran con un signo de interrogación:
Y el signo de exclamación en este caso es equivalente a acceder a la propiedad .Value del tipo anulable de esta manera:
fuente
En el objetivo C, las variables sin valor eran iguales a 'nulo' (también era posible usar valores 'nulo' igual a 0 y falso), por lo tanto, era posible usar variables en declaraciones condicionales (las variables que tienen valores son iguales a 'VERDADERO' 'y aquellos sin valores eran iguales a' FALSO ').
Swift proporciona seguridad de tipo al proporcionar 'valor opcional'. es decir, evita errores formados al asignar variables de diferentes tipos.
Entonces, en Swift, solo se pueden proporcionar booleanos en las declaraciones condicionales.
Aquí, aunque 'hw' es una cadena, no se puede usar en una declaración if como en el objetivo C.
Para eso necesita ser creado como,
fuente
Los ! al final de un objeto dice que el objeto es opcional y que se desenvuelve si de lo contrario puede devolver un valor nulo. Esto a menudo se usa para atrapar errores que de otro modo bloquearían el programa.
fuente
En resumen (!): Después de declarar una variable y de estar seguro de que la variable tiene un valor.
de lo contrario, tendría que hacer esto cada vez que pase el valor ...
fuente
John es una persona opcional, lo que significa que puede tener un valor o ser nulo.
se usa si juan no es un opcional. Como John nunca es nulo, podemos estar seguros de que no llamará a un apartamento con un valor nulo. Mientras
promete al compilador que John no es nulo, luego desenvuelve lo opcional para obtener el valor de John y accede a la propiedad del apartamento de John. Use esto si sabe que John no es nulo. Si llama a esto en un cero opcional, obtendrá un error de tiempo de ejecución.
La documentación incluye un buen ejemplo para usar esto donde convertNumber es opcional.
fuente
john.apartment = number73
, eso NO dará como resultado un error a menos que ponga un '!' despues de john?john
opcional le dice al compilador que necesito que no sea nulo? ... Y en suvar jack: Person = john!
ejemplo, ¿no es la falta de un? ¿Después de que la persona le dice al compilador que necesitajohn
ser no nulo? En general, lo que!
parece parece un poco redundante ... Todavía siento que me falta algo en la parte del "por qué" de!
...En pocas palabras, los signos de exclamación significan que se está desenvolviendo un opcional. Un opcional es una variable que puede tener un valor o no, por lo que puede verificar si la variable está vacía, utilizando una instrucción if let como se muestra aquí , y luego forzar el desenvolvimiento. Sin embargo, si fuerza a desenvolver un opcional que está vacío, su programa se bloqueará, ¡así que tenga cuidado! Las opciones se declaran poniendo un signo de interrogación al final de una asignación explícita a una variable, por ejemplo, podría escribir:
Esta variable no tiene valor. Si lo desenvolviera, el programa se bloquearía y Xcode le diría que intentó desenvolver un opcional con un valor nulo.
Espero que haya ayudado.
fuente
En palabras simples
USANDO El signo de exclamación indica que la variable debe constar de un valor nulo (nunca será nulo)
fuente
Toda la historia comienza con una característica de swift llamada vars opcionales. Estos son los vars que pueden tener un valor o no tener un valor. En general, swift no nos permite usar una variable que no está inicializada, ya que esto puede provocar bloqueos o razones inesperadas y también un servidor de marcador de posición para puertas traseras. Por lo tanto, para declarar una variable cuyo valor no se determina inicialmente, usamos un '?'. Cuando se declara dicha variable, para usarla como parte de alguna expresión hay que desenvolverla antes de usarla, desenvolver es una operación a través de la cual se descubre el valor de una variable que se aplica a los objetos. Sin desenvolver si intentas usarlos, tendrás un error de tiempo de compilación. Para desenvolver una variable que es una var opcional, el signo de exclamación "!" es usado
Ahora hay momentos en que sabe que a tales variables opcionales se les asignarán valores por sistema, por ejemplo, o por su propio programa, pero en algún momento posterior, por ejemplo, salidas de interfaz de usuario, en tal situación en lugar de declarar una variable opcional usando un signo de interrogación "?" usamos "!".
Así, el sistema sabe que esta variable que se declara con "!" es opcional en este momento y no tiene valor, pero recibirá un valor más adelante en su vida útil.
Por lo tanto, el signo de exclamación tiene dos usos diferentes: 1. Para declarar una variable que será opcional y recibirá un valor definitivamente más tarde 2. Para desenvolver una variable opcional antes de usarla en una expresión.
Las descripciones anteriores evitan demasiadas cosas técnicas, espero.
fuente
Si lo usa como opcional, desenvuelve el opcional y ve si hay algo allí. Si lo usa en una declaración if-else, es un código para NOT. Por ejemplo,
fuente
Una variable opcional puede contener un valor o no
caso 1:
var myVar:String? = "Something"
caso 2:
var myVar:String? = nil
ahora si le preguntas a myVar !, le estás diciendo al compilador que devuelva un valor en el caso 1, devolverá
"Something"
en el caso 2 se bloqueará.
Sentido ! mark forzará al compilador a devolver un valor, incluso si no está allí. Es por eso que el nombre Force Unwrapping .
fuente
fuente
PREGÚNTESE
person?
tiene unapartment
miembro / propiedad? Operson
tiene unapartment
miembro / propiedad?Si no puede responder esta pregunta, continúe leyendo:
Para comprenderlo, es posible que necesite un nivel súper básico de comprensión de los genéricos . Ver aquí . Muchas cosas en Swift se escriben usando genéricos. Opcionales incluidos
El siguiente código se ha puesto a disposición en este video de Stanford . Le recomiendo que mire los primeros 5 minutos
Un opcional es una enumeración con solo 2 casos
Encuadernación opcional:
cuando dices
var john: Person?
que realmente quieres decir eso:¿La enumeración anterior tiene alguna propiedad nombrada
apartment
? ¿Lo ves en alguna parte? Es que no hay en absoluto! Sin embargo, si lo desenvuelve, es decir,person!
puede ... lo que hace debajo del capó es:Optional<Person>.Some(Person(name: "John Appleseed"))
Si hubiera definido en
var john: Person
lugar de:var john: Person?
entonces ya no habría necesitado tener el!
usado, porquePerson
sí tiene un miembro deapartment
Como una discusión futura sobre por qué
!
a veces no se recomienda usar para desenvolver, vea estas preguntas y respuestasfuente