DEV Community

Cover image for Optional em Swift
Matheus dos Reis de Jesus
Matheus dos Reis de Jesus

Posted on

Optional em Swift

Capa por Ana Municio no Unsplash

Sumário

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
Enter fullscreen mode Exit fullscreen mode

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!")
Enter fullscreen mode Exit fullscreen mode

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!)
Enter fullscreen mode Exit fullscreen mode

O trecho abaixo dispararia a seguinte exceção:

Unexpectedly found nil while unwrapping an Optional value
Enter fullscreen mode Exit fullscreen mode

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"
Enter fullscreen mode Exit fullscreen mode

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?'
     */
}
Enter fullscreen mode Exit fullscreen mode

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 ...
}

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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!👋🏽

Top comments (2)

Collapse
 
luizrebelatto profile image
Luiz Gabriel

Artigo muito bom, consegui consolidar melhor meu entendimento sobre optinals!

Collapse
 
reisdev profile image
Matheus dos Reis de Jesus

Fico feliz que tenha sido útil pra você, Luiz!