O que significa "desembrulhar a instância"? Por que isso é necessário?
Tanto quanto eu posso trabalhar (isso também é muito novo para mim) ...
O termo "embrulhado" implica que devemos pensar em uma variável opcional como um presente, embrulhado em papel brilhante, que pode (infelizmente!) Estar vazio .
Quando "empacotado", o valor de uma variável Opcional é uma enumeração com dois valores possíveis (um pouco como um Booleano). Esta enumeração descreve se a variável possui um valor ( Some(T)
) ou não ( None
).
Se houver um valor, isso pode ser obtido "desembrulhando" a variável (obtendo a T
partir de Some(T)
).
Qual é a john!.apartment = number73
diferença john.apartment = number73
? (Parafraseado)
Se você escrever o nome de uma variável Opcional (por exemplo john
, texto , sem a !
), isso se refere à enumeração "empacotada" (Alguma / Nenhuma), não ao valor em si (T). Portanto, john
não é uma instância de Person
e não possui um apartment
membro:
john.apartment
// 'Person?' does not have a member named 'apartment'
O Person
valor real pode ser desembrulhado de várias maneiras:
- "desembrulhar forçado":
john!
(fornece o Person
valor, se existir, erro de tempo de execução, se for nulo)
- "ligação opcional":
if let p = john { println(p) }
(executa println
se o valor existe)
- "encadeamento opcional":
john?.learnAboutSwift()
(executa este método inventado se o valor existir)
Eu acho que você escolhe uma dessas maneiras de desembrulhar, dependendo do que deve acontecer no caso nulo e da probabilidade disso. Esse design de linguagem força o caso nulo a ser tratado explicitamente, o que eu suponho melhora a segurança em relação ao Obj-C (onde é fácil esquecer o tratamento do caso nulo).
Atualização :
O ponto de exclamação também é usado na sintaxe para declarar "Opcionais Implicitamente Desembrulhados".
Nos exemplos até agora, a john
variável foi declarada como var john:Person?
e é uma Opcional. Se você deseja o valor real dessa variável, deve desembrulhá-la, usando um dos três métodos acima.
Se fosse declarada como var john:Person!
alternativa, a variável seria um opcional implicitamente desembrulhado (consulte a seção com este cabeçalho no livro da Apple). Não há necessidade de desembrulhar esse tipo de variável ao acessar o valor e john
pode ser usado sem sintaxe adicional. Mas o livro da Apple diz:
Opcionais implicitamente desembrulhados não devem ser usados quando houver a possibilidade de uma variável se tornar nula posteriormente. Sempre use um tipo opcional normal se precisar verificar um valor nulo durante a vida útil de uma variável.
Atualização 2 :
O artigo " Recursos rápidos e interessantes " de Mike Ash fornece alguma motivação para os tipos opcionais. Eu acho ótimo escrever com clareza.
Atualização 3 :
Outro artigo útil sobre o uso opcional implicitamente desembrulhado do ponto de exclamação: " Swift and the Last Mile ", de Chris Adamson. O artigo explica que essa é uma medida pragmática da Apple usada para declarar os tipos usados por suas estruturas de Objective-C que podem conter nulo. Declarar um tipo como opcional (usando ?
) ou desembrulhado implicitamente (usando !
) é "uma troca entre segurança e conveniência". Nos exemplos dados no artigo, a Apple optou por declarar os tipos como implicitamente desembrulhados, tornando o código de chamada mais conveniente, mas menos seguro.
Talvez a Apple possa vasculhar suas estruturas no futuro, removendo a incerteza de parâmetros implicitamente desembrulhados ("provavelmente nunca nulos") e substituindo-os por parâmetros opcionais ("certamente poderia ser nulo em particular [espero, documentado!] Circunstâncias") ou não padrão -opcional ("nunca é nulo"), com base no comportamento exato do código Objective-C.
Aqui está o que eu acho que é a diferença:
Significa que john pode ser nulo
O compilador interpretará essa linha como:
Enquanto
O compilador interpretará essa linha como simplesmente:
Portanto, usando! desempacotará a instrução if e a executará mais rapidamente, mas se john for nulo, ocorrerá um erro de tempo de execução.
Então, agrupar aqui não significa que é agrupado em memória, mas significa que é agrupado em código; nesse caso, é agrupado com uma instrução if e, como a Apple presta muita atenção ao desempenho em tempo de execução, eles querem oferecer uma maneira de faça seu aplicativo funcionar com o melhor desempenho possível.
Atualizar:
Voltando a esta resposta após 4 anos, pois obtive a maior reputação no Stackoverflow :) Eu entendi um pouco o significado de desembrulhar na época. Agora, depois de quatro anos, acredito que o significado de desembrulhar aqui é expandir o código de sua forma compacta original. Também significa remover a imprecisão em torno desse objeto, pois, por definição, não temos certeza se é nulo ou não. Assim como a resposta de Ashley acima, pense nisso como um presente que não pode conter nada. Mas ainda acho que o desempacotamento é desembrulhado por código e não desempacotado com base na memória como usando enum.
fonte
TL; DR
O que significa um ponto de exclamação no idioma Swift?
Exemplo
Fonte: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid/TP40014097-CH5-XID_399
fonte
let f: String! = "hello"
e entãoprint(f)
, a saída é emOptional("hello")
vez de apenas"hello"
.Se john fosse um var opcional (declarado assim)
seria possível que john não tivesse valor (na linguagem ObjC, valor nulo)
O ponto de exclamação basicamente diz ao compilador "Eu sei que isso tem um valor, você não precisa testá-lo". Se você não quiser usá-lo, poderá testá-lo condicionalmente:
O interior disso avaliará apenas se john tem um valor.
fonte
“let possibleString: String? = "An optional string." println(possibleString!) // requires an exclamation mark to access its value // prints "An optional string.”
Mas funciona bem sem! Algo parece estranho aqui.John?
eJohn
são dois tipos diferentes. Um é do tipo Pessoa Opcional e o outro Tipo Pessoa. O Person opcional precisa ser desembrulhado antes que você possa tirá-lo. Mas, como você diz, isso parece acontecer pelo menos nessas circunstâncias sem ter que realmente fazer nada. Isso parece fazer o! redundante. A menos que o! SEMPRE é opcional, mas é recomendável sugerir erros de compilação. Como atribuir vars / lets a um tipo específico, pode ser explícito,let John: Person = ...
mas também pode ser inferidolet John = ...
.Alguma perspectiva geral para adicionar a outras respostas úteis, mas mais centradas em detalhes:
No Swift, o ponto de exclamação aparece em vários contextos:
let name = nameLabel!.text
var logo: UIImageView!
logo.image = thing as! UIImage
try! NSJSONSerialization.JSONObjectWithData(data, [])
Cada uma delas é uma construção de linguagem diferente, com um significado diferente, mas todas elas têm três coisas importantes em comum:
1. Os pontos de exclamação contornam as verificações de segurança em tempo de compilação do Swift.
Quando você usa o
!
Swift, está basicamente dizendo: “Ei, compilador, eu sei que você acha que um erro pode acontecer aqui, mas eu sei com total certeza que isso nunca acontecerá".Nem todo código válido se encaixa na caixa do sistema de tipos de tempo de compilação do Swift - ou na verificação estática de qualquer tipo de idioma, nesse caso. Há situações em que você pode provar logicamente que nunca ocorrerá um erro, mas não o poderá provar ao compilador . É por isso que os designers da Swift adicionaram esses recursos em primeiro lugar.
No entanto, sempre que você usa
!
, está descartando um caminho de recuperação para um erro, o que significa que…2. Pontos de exclamação são possíveis falhas.
Um ponto de exclamação também diz: "Hey Swift, tenho tanta certeza de que esse erro nunca pode acontecer que é melhor você travar meu aplicativo inteiro do que codificar um caminho de recuperação para ele".
Essa é uma afirmação perigosa. ele pode ser o correto: no código de missão crítica, onde você tem pensado muito sobre invariantes do seu código, pode ser que a saída falsa é pior do que um acidente.
No entanto, quando vejo
!
na natureza, raramente é usado com tanta atenção. Em vez disso, muitas vezes significa: "esse valor era opcional e eu realmente não pensei muito sobre por que poderia ser nulo ou como lidar adequadamente com essa situação, mas a adição!
fez com que fosse compilada ... para que meu código esteja correto, certo?"Cuidado com a arrogância do ponto de exclamação. Em vez de…
3. Os pontos de exclamação são melhor usados com moderação.
Cada uma dessas
!
construções possui uma?
contraparte que o força a lidar com o caso de erro / zero:if let name = nameLabel?.text { ... }
var logo: UIImageView?
logo.image = thing as? UIImage
try? NSJSONSerialization.JSONObjectWithData(data, [])
Se você é tentado a usar
!
, é sempre bom considerar cuidadosamente por que você não está usando?
. Falhando no seu programa é realmente a melhor opção se a!
operação falhar? Por que esse valor é opcional / disponível?Existe um caminho de recuperação razoável que seu código poderia seguir no caso de nulo / erro? Se sim, codifique-o.
Se não puder ser nulo, se o erro nunca ocorrer, existe uma maneira razoável de refazer sua lógica para que o compilador saiba disso? Se sim, faça; seu código será menos propenso a erros.
Há momentos em que não há uma maneira razoável de lidar com um erro, e simplesmente ignorá-lo - e, assim, prosseguir com dados errados - seria pior do que travar. Esses são os momentos para usar a força de desembrulhar.
Eu procuro periodicamente toda a minha base de código
!
e audito cada uso dela. Muito poucos usos resistem ao escrutínio. (Até o momento em que este artigo foi escrito, toda a estrutura do Siesta possui exatamente duas instâncias .)Isso não quer dizer que você nunca deve usar
!
seu código - apenas que você deve usá-lo com atenção e nunca torná-lo a opção padrão.fonte
func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { if(receiptData == nil) { return false; } return (hasValidTrial(receiptData!) || isNotExpired(receiptData!)) && isNotCancelled(receiptData!) }
Dado 3. existe uma maneira melhor de escrever?func isSubscriptionActive(receiptData: NSDictionary?) -> Bool { guard let nonNilReceiptData = receiptData else { return false} return (hasValidTrial(nonNilReceiptData) || isNotExpired(nonNilReceiptData)) && isNotCancelled(nonNilReceiptData) }
john
é um opcionalvar
. Então pode ser contém umnil
valor. Para garantir que o valor não seja nulo, use a!
no final dovar
nome.Da documentação
“Depois de ter certeza de que o opcional contém um valor, você pode acessar o valor subjacente adicionando um ponto de exclamação (!) Ao final do nome do opcional. O ponto de exclamação diz efetivamente: “Eu sei que esse opcional definitivamente tem um valor; por favor, use-o. ”
Outra maneira de verificar o valor não nulo é
fonte
john.apartment = number73
também diz "Eu sei que esse opcional definitivamente tem um valor; por favor, use-o." ...aqui estão alguns exemplos:
Onde
word
é um valor opcional. significa que pode ou não conter um valor.Aqui
name
tem um valor para que possamos atribuí-loOnde
dog
for desembrulhado com força significa que deve conter um valorO aplicativo falhará porque somos atribuídos
nil
a desembrulhadosfonte
var c:Int = nil
irá receber: "Nil não pode inicializar o tipo especificado 'int'"Nesse caso...
var John: Pessoa!
significa que, inicialmente, John terá valor nulo, será definido e, uma vez definido, nunca será nulo novamente. Portanto, por conveniência, posso usar a sintaxe mais fácil para acessar uma var opcional, porque esta é uma "Opcional implicitamente desembrulhada"
fonte
Se você veio de uma linguagem da família C, estará pensando em "ponteiro para objeto do tipo X, que pode ser o endereço de memória 0 (NULL)", e se você vier de uma linguagem de tipo dinâmico, será pensando "Objeto que provavelmente é do tipo X, mas pode ser do tipo indefinido". Nenhuma delas está realmente correta, embora de maneira indireta a primeira esteja próxima.
A maneira como você deve pensar nisso é como se fosse um objeto como:
Quando você está testando seu valor opcional,
foo == nil
ele realmente está retornandofoo.isNil
e quando você dizfoo!
que está retornandofoo.realObject
com uma afirmação de quefoo.isNil == false
. É importante observar isso, porque sefoo
realmente for nulo quando você fazfoo!
isso, é um erro de tempo de execução; portanto, normalmente você deseja usar uma permissão condicional, a menos que tenha certeza de que o valor não será nulo. Esse tipo de truque significa que o idioma pode ser fortemente digitado sem forçar você a testar se os valores são nulos em todos os lugares.Na prática, ele realmente não se comporta assim porque o trabalho é feito pelo compilador. Em um nível alto, há um tipo
Foo?
que é separadoFoo
e impede que as funções que aceitam o tipoFoo
recebam um valor nulo, mas, em um nível baixo, um valor opcional não é um objeto verdadeiro porque não possui propriedades ou métodos; é provável que, de fato, seja um ponteiro que pode, por NULL (0), com o teste apropriado ao desembrulhar à força.Há outra situação em que você vê um ponto de exclamação em um tipo, como em:
Isso é aproximadamente equivalente a aceitar um opcional com um desembrulhamento forçado, ou seja:
Você pode usar isso para ter um método que aceite tecnicamente um valor opcional, mas que terá um erro de tempo de execução se for nulo. Na versão atual do Swift, isso aparentemente ignora a asserção não é nada, então você terá um erro de baixo nível. Geralmente não é uma boa ideia, mas pode ser útil ao converter código de outro idioma.
fonte
O ! significa que você está forçando a desembrulhar o objeto! segue. Mais informações podem ser encontradas na documentação da Apple, que pode ser encontrada aqui: https://developer.apple.com/library/ios/documentation/swift/conceptual/Swift_Programming_Language/TheBasics.html
fonte
Se você conhece C #, são tipos Nullable que também são declarados usando um ponto de interrogação:
E o ponto de exclamação, neste caso, é equivalente a acessar a propriedade .Value do tipo anulável como este:
fonte
No objetivo C, variáveis sem valor eram iguais a 'nil' (também era possível usar valores 'nil' iguais a 0 e false); portanto, era possível usar variáveis em declarações condicionais (variáveis com valores iguais a 'TRUE 'e aqueles sem valores foram iguais a' FALSE ').
Swift fornece segurança de tipo, fornecendo 'valor opcional'. ou seja, evita erros formados de atribuir variáveis de tipos diferentes.
Portanto, no Swift, apenas booleanos podem ser fornecidos em instruções condicionais.
Aqui, mesmo que 'hw' seja uma string, ela não pode ser usada em uma instrução if como no objetivo C.
Para isso, ele precisa ser criado como,
fonte
O ! no final de um objeto, o objeto é opcional e é desembrulhado, se puder retornar um valor nulo. Isso geralmente é usado para capturar erros que, de outra forma, travariam o programa.
fonte
Resumindo (!): Depois de declarar uma variável e ter certeza de que a variável está mantendo um valor.
caso contrário, você teria que fazer isso sempre que passar o valor ...
fonte
João é uma Pessoa opcional, o que significa que pode conter um valor ou ser nulo.
é usado se john não for opcional. Como john nunca é nulo, podemos ter certeza de que não chamará apartamento com um valor nulo. Enquanto
promete ao compilador que john não é nulo, desembrulha o opcional para obter o valor de john e acessa a propriedade do apartamento de john. Use isso se você souber que john não é nulo. Se você chamar isso de opcional nulo, você receberá um erro de tempo de execução.
A documentação inclui um bom exemplo para usá-lo, em que convertNumber é opcional.
fonte
john.apartment = number73
, isso não resultará em erro, a menos que eu coloque um '!' depois de john?john
opcional diz ao compilador que eu preciso que ele não seja nulo? ... E no seuvar jack: Person = john!
exemplo, a falta de um? depois de Person dizer ao compilador que você precisajohn
ser não nulo? No geral, a!
apenas parece parece meio redundante ... Ele ainda se sente como eu estou faltando alguma coisa sobre o "porquê" parte do!
...Simplificando, pontos de exclamação significam que um opcional está sendo desembrulhado. Uma opcional é uma variável que pode ter um valor ou não - para que você possa verificar se a variável está vazia, usando uma instrução if let, como mostrado aqui , e depois forçar a desembrulhar. Se você forçar a desembrulhar um opcional vazio, seu programa falhará, portanto, tenha cuidado! Os opcionais são declarados colocando um ponto de interrogação no final de uma atribuição explícita a uma variável, por exemplo, eu poderia escrever:
Esta variável não tem valor. Se eu o desembrulhasse, o programa falharia e o Xcode lhe diria que você tentou desembrulhar um opcional com um valor nulo.
Espero que tenha ajudado.
fonte
EM PALAVRAS SIMPLES
USANDO O ponto de exclamação indica que a variável deve consistir em um valor nulo (nunca será nulo)
fonte
Toda a história começa com um recurso rápido chamado vars opcionais. Estes são os vars que podem ter um valor ou podem não ter um valor. Em geral, o swift não nos permite usar uma variável que não foi inicializada, pois isso pode levar a falhas ou razões inesperadas e também servir como um espaço reservado para backdoors. Assim, para declarar uma variável cujo valor não é determinado inicialmente, usamos um '?'. Quando uma variável é declarada, para usá-la como parte de alguma expressão que é necessária para desembrulhá-la antes do uso, desembrulhar é uma operação pela qual o valor de uma variável é descoberto, isso se aplica aos objetos. Sem desembrulhar, se você tentar usá-los, terá um erro de tempo de compilação. Para desembrulhar uma variável que é uma var opcional, ponto de exclamação "!" é usado.
Agora, há momentos em que você sabe que essas variáveis opcionais receberão valores pelo sistema, por exemplo, ou por seu próprio programa, mas algum tempo depois, por exemplo, pontos de interface do usuário, nessa situação, em vez de declarar uma variável opcional usando um ponto de interrogação "?" nós usamos "!".
Assim, o sistema sabe que essa variável que é declarada com "!" é opcional no momento e não tem valor, mas receberá um valor posteriormente.
Assim, o ponto de exclamação possui dois usos diferentes: 1. Declarar uma variável que será opcional e receberá valor definitivamente mais tarde 2. Desembrulhar uma variável opcional antes de usá-la em uma expressão.
As descrições acima evitam muito material técnico, espero.
fonte
Se você o usar como opcional, ele desembrulha o opcional e verifica se há algo lá. Se você usá-lo em uma instrução if-else is é código para NOT. Por exemplo,
fonte
Uma variável opcional pode conter um valor ou pode não ser
caso 1:
var myVar:String? = "Something"
caso 2:
var myVar:String? = nil
Agora, se você perguntar ao myVar !, você está dizendo ao compilador para retornar um valor no caso 1, ele retornará
"Something"
no caso 2, ele travará.
Significado! A marca forçará o compilador a retornar um valor, mesmo que não esteja lá. é por isso que o nome Force Unwrapping .
fonte
fonte
PERGUNTE-SE
person?
tem umapartment
membro / propriedade? OUperson
tem umapartment
membro / propriedade?Se você não conseguir responder a essa pergunta, continue lendo:
Para entender, você pode precisar de um nível super básico de compreensão de genéricos . Veja aqui . Muitas coisas no Swift são escritas usando Genéricos. Opcionais incluídos
O código abaixo foi disponibilizado neste vídeo de Stanford . Recomendo que você assista os primeiros 5 minutos
Um opcional é um enum com apenas 2 casos
Ligação opcional:
quando você diz que
var john: Person?
realmente quer dizer isso:A enumeração acima tem alguma propriedade chamada
apartment
? Você vê em algum lugar? É não existe em tudo! No entanto, se você desembrulhá-lo, ou sejaperson!
, você pode ... o que ele faz sob o capô é:Optional<Person>.Some(Person(name: "John Appleseed"))
Se você tivesse definido em
var john: Person
vez de:var john: Person?
então não precisaria mais ter o!
usado, porquePerson
ele próprio tem um membro deapartment
Como uma discussão futura sobre por que o uso
!
do desembrulhar às vezes não é recomendado, consulte esta seção de perguntas e respostasfonte