DEV Community

Cover image for Opcionais no Swift
Danilo Barreto
Danilo Barreto

Posted on

Opcionais no Swift

Você já viu um monte de códigos no Swift com "?" e "!" e fica perdido? Usa esses operadores mas sem saber direito quando e onde usar? Esse post então é pra você.

O que é um "?" no Swift

O símbolo "?" representa um opcional no Swift. E um opcional é (pasmem) um enum: .Some(Valor Encapsulado) e .None. Isso permite que ele possa ser vazio (.None) ou possa ter algum valor internamente (.Some(valor).

Exemplo:

var x: Int? = 10
Enter fullscreen mode Exit fullscreen mode

Ao criar uma variável com "?", no caso Int? o Swift cria um enum do tipo Optional mas com o estado .Some(10).

var x: Int? = nil
Enter fullscreen mode Exit fullscreen mode

Caso contrário, se você atribui nil, é criada uma variável do tipo Optional com o estado .None

Comparação

Sabendo agora como é armazenado um Opcional, o Swift oferece algumas formas de trabalhar com ele. Podemos comparar ele de algumas formas:

let x: Int? = 10

switch x{
   case .Some(let value) : print("Valor de x \(value)")
   case .None : print("x não tem valor")
}
Enter fullscreen mode Exit fullscreen mode

Uma boa prática é "desembrulhar" (do inglês unwrap) o valor da váriavel de forma segura usando o guard. O guard pode ser executado da seguinte forma:

func foo(x: Int?){
   guard let y = x else{
      return
   }
   print(y)
}
Enter fullscreen mode Exit fullscreen mode

Encadeamento Opcional

O encadeamento opcional permite você pegar o valor de dentro de um opcional. Diferente do Unwrapping Forçado que vou falar a seguir, ele não causa um erro caso não tenha um valor dento do Opcional. Vamos ao exemplo:

var x: Int? = 10 // .Some(10)
var y: Int = x? // 10
Enter fullscreen mode Exit fullscreen mode

No exemplo simples acima quando eu chamo x? eu faço um unwrapping do Opcional, ou seja, eu pego somente o valor que existe dentro dele. Vamos para um exemplo um pouco mais complexo. Considere o código:

class Person{
   var residence: Residence?
}

class Residence{
   var numberOfRooms = 1
}
Enter fullscreen mode Exit fullscreen mode

Agora considere a seguinte função:

func foo(){
   let john = Person()
   if let roomCount = john.residence?.numberOfRooms{
      print("Número de quartos \(roomCount)")
   } else {
      print("Não foi possível determinar o número de quartos")
   }
}
Enter fullscreen mode Exit fullscreen mode

O trecho de código acima não irá produzir um erro, pois o encadeamento opcional sempre retornar um Opcional que pode ser comparado. Mas ele será nil. Então sua condição irá cair no else. Mas se mudarmos aqui:

func foo(){
   let john = Person()
   john.residence = Residence()
   if let roomCount = john.residence?.numberOfRooms{
      print("Número de quartos \(roomCount)")
   } else {
      print("Não foi possível determinar o número de quartos")
   }
}
Enter fullscreen mode Exit fullscreen mode

O retorno será 1, pois é o valor padrão da quantidade de quartos.

Unwrapping Forçado

O unwrapping forçado tem uma sintaxe parecida, trocando apenas "?" por "!". Mas ele tem uma diferença fundamental: Caso o valor no Opcional seja nil, é gera um erro de execução e o aplicativo irá encerrar, caso não tratado. Utilizando o exemplo acima:

func foo(){
   let john = Person()
   if let roomCount = john.residence!.numberOfRooms{ //o app irá quebrar nessa linha
      print("Número de quartos \(roomCount)")
   } else {
      print("Não foi possível determinar o número de quartos")
   }
}
Enter fullscreen mode Exit fullscreen mode

o unwrapping forçado só deve ser usado caso você tenha ABSOLUTA CERTEZA de que o Opcional tenha valor.

Coalescência

O operador de coalescência "??" permite que você retorne o primeiro valor não nulo (nil) de duas variáveis. Vamos deixar mais claro no exemplo:

let c: Int? = 10
let d: Int = 0
let e = c ?? d //o valor de e será 10
Enter fullscreen mode Exit fullscreen mode

No exemplo acima prevalece o primeiro valor não nil. Segundo exemplo:

let c: Int? = nil
let d: Int = 5
let e = c ?? d //o valor de e será 5
Enter fullscreen mode Exit fullscreen mode

Como no exemplo acima c é nil, o valor de e será 5, o primeiro valor não nil.

BONUS ADVANCED: Map e FlatMap

O tipo Opcional ainda oferece duas funções chamadas Map e Flatmap que permitem que você controle o método de unwrapping passando um closure. A única diferença entro o Map e Flatmap é que o Map não pode devolver nil. Exemplos, exemplos:

var a : Int? = 10

let y : Int?  = a.Map{
   if $0 < 10 {
      return 0
   } else {
      return $0
   }
}

let z : Int? = a.FlatMap{
   if $0 < 10 {
      return nil
   } else {
      return $0
   }
}
Enter fullscreen mode Exit fullscreen mode

É isso gente. Esse é todo o "mistério" dos Opcionais no Swift. A partir de agora você já sabe ler quando encontrar "?" e "!" nos códigos e sabe como posicionar nos seus próprios códigos.

Até a próxima! Keep coding!

Top comments (0)