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