Optional em Swift
Saber usar variáveis Optional em Swift pode garantir maior confiabilidade no seu código e evitar que erros indesejados aconteçam.
Capa por Ana Municio no Unsplash
Introdução
É possível criar variáveis em Swift que não necessariamente tenham um valor definido(ou seja, nulo) e elas são conhecidas como opcionais. Para que uma variável não tenha valor usamos o valor nil
. Definimos uma variável como opcional colocando uma interrogação após a definição do seu tipo, da seguinte forma:
var minhaString: String? = nil
print(minhaString)
// Saída: nil
A partir dessa atribuição, a variável minhaString
ainda não tem valor definido. Agora, podemos tentar atribuir um valor à minhaString
e verificar o resultado:
var minhaString: String? = "Olá mundo!"
print(minhaString)
// Saída: Optional("Olá mundo!")
Lidando com Optional
Lidar com variáveis opcionais requer um pouco mais de atenção, pois é importante verificar se essa variável possui valor antes de utilizá-lo em algum trecho de código. Para isso, temos 4 opções:
- Usando o force unwrapping, com
!
- Usando binding opcional, com
if let
- Usando o unwrapping implícito de opcionais, com
!
- Usando encadeamento opcional, com
a?.b?.c
- Usando unwrapping incondicional
Force unwrapping
Force unwrapping, que pode ser traduzido como "forçar a desembrulhar" é a forma explicita de extrair o valor de um Optional
. Ele pode ser usado, por exemplo, em um parâmetro de uma função que não pode ser nil
, dessa forma:
// O parâmetro 'nome' não é opcional
func minhaFuncao(nome: String) {
print("Olá, \(nome)")
}
// A variável 'meuNome'é opcional e tem valor 'nil'
var meuNome: String? = nil
minhaFuncao(nome: meuNome!)
O trecho abaixo dispararia a seguinte exceção:
Unexpectedly found nil while unwrapping an Optional value
Por quê? Pelo fato de que o valor da variável meuNome
foi atribuído como nil
. Portanto, é importante ter em mente que, para usar o force unwrapping, é necessário atender pelo menos um dos seguintes critérios:
- Ter certeza de que o valor está definido
- Tratar a exceção que será lançada caso o valor seja
nil
Se o valor da variável meuNome
não fosse nil
, o resultado seria diferente:
func minhaFuncao(nome: String) {
print("Olá, \(nome)")
}
var meuNome: String? = "ReisDev"
minhaFuncao(nome: meuNome!)
// Saída: "Olá, ReisDev"
O uso do force unwrapping não é recomendado por conta dos erros que ele pode ocasionar caso alguma variável tenha o valor nil
. Por isso, use com cautela.
Binding opcional
if let
Optional binding, que pode ser traduzido como "amarração opcional", consiste em garantir que um trecho de código será executado apenas se um determinado valor não for nil
. Inclusive, é possível verificar sub-condições, como atributos de objetos. Abaixo, um exemplo de uso:
var meuTexto: String? = nil
if let texto = meuTexto {
/*
* Nesse contexto, a variável texto é
* do tipo String, e não 'String?'
*/
}
No bloco de código acima, o trecho contido entre as chaves é chamado de closure
, e você pode ver mais detalhes neste link(em inglês). Dentro dessa closure a variável texto
(que recebeu o valor da variável meuTexto
) é do tipo String
por conta da amarração opcional. Se o valor da variável meuTexto
não for nil
, ele será "amarrado" à variável texto
, e o trecho de código dentro da closure será executado.
guard let
Além do if let
, podemos usar também o guard let
, que valida se uma variável tem valor e, caso não tenha, executa um trecho de código que deve encerrar a execução, seja do programa ou de uma função. Abaixo, um exemplo:
func validaTexto(meuTexto: String?) -> Bool {
guard let texto = meuTexto else {
return false
}
// Valida o texto ...
}
Unwrapping implícito
O unwrapping implícito, que pode ser traduzido como "desembrulhamento" implícito, é usado para evitar ter que usar as outras abordagens citadas nesse artigo para obter o valor de uma variável Optional
. Ele funciona da seguinte forma:
var pessoa: Pessoa! = nil
Como a variável pessoa
é do tipo Pessoa?
(sem o unwrapping implícito), se tentarmos acessar o atributo endereco
, por exemplo, obteríamos o seguinte erro:
value of optional type 'Pessoa?' must be unwrapped to refer to member 'endereco' of wrapped base type 'Pessoa'
Por quê? O compilador da linguagem sabe que é arriscado acessar uma variável Optional
sem a garantia de que ela de fato tem um valor, pois isso pode causar um erro. Por isso, ele tenta garantir que quem está escrevendo o código faça essa verificação.
O unwrapping implícito é usado exatamente para não precisar fazer essa verificação todas as vezes. Parece prático, mas também pode ser arriscado. Se você utilizar esse recurso, tenha o cuidado de tratar exceções, pois pode acontecer de sua variável ter o valor nil
, e isso irá ocasionar em um erro. O uso desse recurso não é encorajado, por conta dos problemas que ele pode gerar. Por isso, Use com moderação.
Encadeamento opcional
Optional chaining, que pode ser traduzido como "encadeamento opcional", é usado, por exemplo, quando se tem atributos de objetos que podem ser nulos, e esses objetos também tem atributos que podem ser nulos. Abaixo, um exemplo:
var minhaRua = pessoa?.endereco?.rua
O objeto pessoa é do tipo Pessoa?
, e o objeto pessoa possui um atributo endereco
do tipo Endereco?
. A variável minhaRua
também será do tipo Optional
, e ela receberá um valor somente se o objeto pessoa
e seu aributo endereco
não forem nil
. Caso algum deles tenha valor nulo, a variável minhaRua
também terá valor nil
.
Unwrapping incondicional
Unconditional unwrapping, que pode ser traduzido como "desembrulhamento incondicional", é usado quando você tem certeza de que um Optional
contém um valor. Abaixo, um exemplo:
var numero = Int("42")!
print(number)
// Saída: 42
No trecho acima, o inicializador de Int
pode falhar, pois a string fornecida pode não conter um número. Porém, nós temos certeza de que "42"
irá resultar em um número. Logo, podemos usar o unconditional unwrapping.
Conclusão
Agora você já sabe como funcionam as variáveis do tipo Optional
e as diferentes maneiras como você pode lidar com elas. Lembre-se sempre de avaliar a forma mais adequada de tratar variáveis opcionais em cada situação. Caso queira saber mais detalhes, recomendo que leia a documentação da Apple.
Gostou deste artigo? Compartilhe e me siga para mais conteúdos como esse!
Minhas redes:
Twitter | Instagram | Blog | Youtube | GitHub | LinkedIn
Até a próxima!👋🏽