Como o Swift IF LET é avaliado?

87

Eu vi esse código no site Swift e vários posts aqui e estou tentando entender o básico. Como esta linha é avaliada?

if let name = optionalName {

Estou confuso, pois não é nome == nome opcional, está atribuindo o valor, então como esse relatório é verdadeiro e por que não é verdadeiro quando você substitui por john appleseed por nil, já que ainda será igual?

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}
DeadZero
fonte
10
Procure "ligação opcional" na documentação do Swift ...
Martin R
3
Uma olhada detalhada nos opcionais em dev.iachieved.it/iachievedit/?p=314 , a if letsintaxe é conhecida como ligação opcional.
Joe

Respostas:

101

Essencialmente, a linha está dizendo, "se você pode deixar a nova variável nameigual à versão não opcional de optionalName, faça o seguinte com ela". Como Martin apontou, isso é chamado de vinculação opcional .

O único propósito disso é testar se uma variável opcional contém um valor real e vincular a forma não opcional a uma variável temporária. Esta é a forma segura de "desembrulhar" um opcional ou, em outras palavras, acessar o valor contido no opcional. Não é de forma alguma um teste de igualdade de qualquer tipo. Ele está apenas testando a existência de um valor dentro de um opcional.

Drewag
fonte
2
Terei uma leitura disso quando chegar a esse ponto, estou apenas no início da introdução rápida e não explica isso. sua explicação faz todo o sentido, obrigado.
DeadZero de
1
Por que não devemos usar "! =" Em vez de "if let" para verificar se a variável opcional tem um valor como - if optionalName! = Nil {greeting = "Hello, (name)"}
Nuibb
4
@Nuibb porque, ao usar if let, vinculamos o valor a uma variável não opcional ( nameneste exemplo). Seu exemplo não compilou porque agora não há nenhuma variável chamada name. Se você alterasse seu exemplo para usá- optionalNamelo, seria impresso como Hello, Optional("John Appleseed"). Você poderia usar o desempacotamento forçado após a verificação contra nil, Hello, \(optionalName!)mas isso é mais sujeito a erros se você mover essa seção do código para algum lugar sem uma verificação.
desenhou em
29

Um opcional é definido ou não definido (não nil ou nil) ... deixando-nos com uma decisão importante. “Como devemos escrever nosso código para que funcione corretamente para 2 ambos os estados?”. A maneira como desembrulhamos o opcional é o que decide isso para nós.

Existem várias abordagens que você pode usar para combater um opcional não definido.

  • Batida!
  • O valor padrão é algo - se não foi definido.
  • Falha graciosamente, ou seja, não faça nada, mas também se o valor foi definido, atribua-o.
  • Falha graciosamente, ou seja, não faça nada, no entanto, se o valor foi definido ... faça algo (é apenas mais do que uma única atribuição).

Abaixo estão as 4 abordagens


Usar o desembrulhamento forçado irá travar se você não tiver um valor. Você gostaria de fazer isso se ter esse valor for de vital importância, por exemplo, o título de um filme (todo filme DEVE ter um nome). !é usado para desembrulhar forçado.

movieTitle = movie.title!

Usar a coalescência nil é outra maneira que lhe dará mais controle , o que significa que não irá travar se o valor não for definido, nem "não definirá nada" se não for definido ... faria o que você disser para fazer, por exemplo, definiria / definiria o nome do filme como untitled_movie se não houvesse nenhum nome definido. ??é usado para coalescência nula.

var movieTitle = movie.title ?? "untitled_Movie"

Usar o encadeamento opcional não fará nada se você não tiver um valor e irá definir o valor se você tiver um valor. Você faz isso para algo cujo valor definido não é de vital importância, por exemplo, para o nome do agente do seu ator . ?é usado para encadeamento opcional.

let agent = movie.leadActor?.agent //would not crash if you don't have a lead actor (optional chaining)
let agent = movie.leadActor!.agent //would crash if you don't have a lead Actor (forced wrapping)  

Usar if-let(ou guardque são dois tipos diferentes de vinculação opcional ) lhe dará mais controle , não travará se o valor não for definido. Se o valor estiver definido, você pode fazer algo. Se não estiver definido, você pode adicionar uma elsedeclaração.

if let supportingActor = movie.supportingActor{
print(" The supporting actor is \(supportingActor)}

Esta é a forma mais comumente usada de desembrulhar, pois o desembrulhamento forçado é um pouco desencorajado. Para mais discussão sobre por que isso é desencorajado, veja aqui . Para uma boa comparação entre guarde if-letvejaguard vs. if-let


Nota:

Encadernação opcional e encadeamento opcional são comumente usados ​​juntos:

if let agent = movie.leadActor?.agent {
ContactInfo = agent.phoneNumber
} // if-let is the optional *binding* part, the movie dot leadActor dot is the optional *chaining*
 
Mel
fonte
Por que o desembrulhamento forçado seria desencorajado em uma situação em que movieTitle nunca pode ser nada além de uma string e todas as strings são válidas para movieTitle? (e eu não quero "filme sem título" Eu quero "") O desembrulhar forçado é a única maneira certa para esta situação, seria ótimo se você pudesse remover a parte que diz "desembrulhar forçado é um pouco desencorajado", pois isso é informação falsa .
Andy
Suponha que você faça uma chamada de rede e algum desenvolvedor da equipe do servidor tome uma decisão errada e se esqueça de enviar o título do filme. Quer que seu aplicativo trave na produção? Ou apenas escreva um título desconhecido? Na verdade, alguns filmes no IMDb não têm títulos :). Além disso, forçar o desempacotamento implica que você não fez nenhum registro ou declaração. Isso é ruim. Porque você não saberá qual foi a causa raiz.
Mel
Esse é um argumento de espantalho, eu nunca disse "use sempre desembrulhamento forçado." Só porque você não deve usar o desembrulhamento forçado em seu exemplo, não significa que o desembrulhamento forçado seja desencorajado em todos os exemplos. Apresentei um cenário em que o desembrulhamento forçado é a única solução certa das quatro que você apresentou. Você pode fornecer uma solução melhor para o cenário declarado em meu comentário anterior? Caso contrário, considere modificar seu comentário sobre "desembrulhar forçado é um pouco desencorajado" porque não é desencorajado sem considerar o contexto.
Andy
Se você está padronizando algo para “”, então não é mais opcional
Honey
Por exemplo, esse valor "" vem da propriedade text de uma instância UILabel criada no storyboard, é opcional porque pode ser nulo se você criá-lo dinamicamente, mas aqui você não o está criando dinamicamente, então sempre conterá um valor de string . Você não vai usar o desembrulhamento forçado neste caso, em vez disso, você iria desembrulhar com if-let e fornecer um valor idêntico ao seu valor padrão ""? Você pode, mas isso é inútil, desnecessário e prolixo. E se você estiver usando uma biblioteca HTTP que sempre retornará um dicionário, mesmo quando for um erro. Depende do contexto.
Andy
4

A sintaxe if aceita 2 condições diferentes. A segunda, uma ligação opcional, não é booleana. Isso é confuso, pois você pode escrever:

if let name = optionalName {

mas não

if (let name = optionalName) {

Documentação da Apple (referência Swift):

O valor da condição deve ser do tipo Boolou um tipo em ponte Bool. A condição também pode ser uma declaração de vinculação opcional, conforme discutido em Vinculação opcional .

Pierre Marty
fonte
3

if só aceita expressões booleanas, exceto que geraria um erro, então este trecho de código dizendo

if let name = optionalName {

}else{

}

se optionalName for nulo, a condição será falsa e a instrução senão será executada. No entanto, se optionalName tiver algum valor, o valor opcional será desempacotado / atribuído à variável constante, ou seja, nome.

Anurag Bhakuni
fonte
1

Sempre que você está trabalhando com referências fracas, tipos opcionais que seria melhor para uso , se deixar a guarda segura seu código e evitar acidentes Eis os exemplos

var middleName :String? = "some thing"
if let isExistsMiddleName = middleName {
// do some thing here
} else {
// no middle name
}
Narendra G
fonte