Quando você faz:
let name = nameField.text
o tipo da constante name
não é String
(como seria o esperado), mas sim String?
-- um tipo optional de String
, ou Optional(String)
--, indicando que pode ser String
ou nil
.
Uma String
"normal" pode ser interpolada com outra String
, como em:
let nomeNaoNulo = "Felipe"
print("Nome: \(nomeNaoNulo)")
Porém um tipo Optional(String)
não pode ser interpolado diretamente, é necessário fazer o seu unboxing, que nada mais é do que recuperar a String
de dentro desse optional tomando o cuidado que ela pode ser nula.
Uma forma simples de fazer o unboxing sem levar em consideração que pode ser nula a String (e levar a erros de null pointer) é usar o operador "!
" assim:
let name = nameField.text
print("eaten \(name!)")
Porém, se esse name
for nulo (nil
), qualquer função chamada na sequência quebraria o código, como em:
let nomeOuNulo : String? = nil
nomeOuNulo!.imprimePrimeiraLetra() //nomeOuNulo! é nil aqui. Logo, crash.
Então, devemos sempre verificar se o tipo optional é nulo antes de qualquer operação, para isso temos diversas funcionalidades na linguagem para nos ajudar, como o if let
e o operador ??
:
O if let
já verifica se a variável é nula e caso contrário já faz seu unboxing automaticamente, assim:
let nomeOuNulo: String? = "Felipe"
if let nomeQueComCertezaNaoEhNulo = nomeOuNulo {
print("Nome: \(nomeQueComCertezaNaoEhNulo)")
} else {
print("Nome nulo")
}
Essa estrutura é a mesma que:
if (nomeOuNulo! != nil) {
let nomeQueComCertezaNaoEhNulo = nomeOuNulo!
print("Nome: \(nomeQueComCertezaNaoEhNulo)")
} else {
print("Nome nulo")
}
Outra forma é o operador ??
que nos permite passar um valor padrão no caso nulo:
let nomeOuNulo : String? = nil
let nome = nomeOuNulo ?? "Sem-nome"
print("Nome: \(nome)") //Nome: Sem-nome
É equivalente a:
let nomeOuNulo : String? = nil
var nome: String = "Sem-nome"
if (nomeOuNulo! != nil) {
nome = nomeOuNulo!
}
print("Nome: \(nome)") //Nome: Sem-nome