DEV Community

Cover image for Opcionais no Swift
Danilo Barreto
Danilo Barreto

Posted on

2 1

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!

Sentry blog image

The Visual Studio App Center’s retiring

But sadly….you’re not. See how to make the switch to Sentry for all your crash reporting needs.

Read more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay