Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Duvidas no uso de enums e completions

O aplicativo esta funcionando normalmente, porem o uso de enums e completions não ficou tão claro pra mim, fiz o que o instrutor pediu meio que sem entender mesmo. Alguém teria alguma recomendação de algum tutorial, curso (aqui da Alura mesmo, ou externo) que deixe mais claro esses tópicos? preferencialmente com em aplicações mais simples, pra ficar fácil de entender.

3 respostas

Enum é um tipo definido no Swift que representa um grupo de valores e permite sua manipulação de uma forma segura ao contar com todas as características que tipagem nos oferece.

Vamos definir no exemplo, uma enum Estado com dois valores: ON e OFF para um botão:

enum Estado {
    case ON
    case OFF
}

Agora, podemos fazer uma função usa esse Estado para algo:

func botao(estado: Estado) {
    if(estado == .ON) {
        print("Botão ligado")
    } else {
        print("Botão desligado")
    }
}

Veja que para sabermos qual o Estado que foi passado para a função temos um if(estado == .ON). Esse .ON pode ser escrito como Estado.ON e é justamente um dos valores que definimos na enum.

Então, ao fazermos

botao(estado: .OFF)
//ou botao(estado: Estado.OFF)

teremos a seguinte saída:

Botão desligado

Podemos passar a própria enum no print. Neste caso, veja como ficará:

func botao(estado: Estado) {
    print("Botão \(estado)")
}

Agora, ao chamarmos botao(estado: .OFF), teremos:

Botão OFF

Veja que por padrão, o nome que damos aos valores da enum viram uma string que pode ser usada em prints, por exemplo.

Podemos também customizar essa string associada aos nossos valores:

enum Estado : String {
    case ON = "ligado"
    case OFF = "desligado"
}

E usá-la na nossa função por meio do método rawValue:

func botao(estado: Estado) {
    print("Botão \(estado.rawValue)")
}

Agora, ao fazemos...

botao(estado: .OFF)

Teremos...

Botão desligado

Veja que agora, não temos o if/else e nossa função continua devolvendo a mesma saída que o primeiro exemplo. A diferença é que usamos melhor a enum.

solução!

Vamos à segunda parte da sua dúvida.

No iOS, podemos passar blocos de código como argumentos de funções, de forma bastante semelhante à lambdas em outras linguagens. Chamamos esses blocos de closures.

Veja esse exemplo:

func teste(closure: () -> Void) {
    print("teste executada")
    closure()
}

Aqui, definimos que nossa função teste receberá uma closure como argumento que terá o seguinte tipo:

() -> Void

Estamos dizendo que seu tipo é "Uma função que recebe zero argumentos e devolve Void".

Dentro da nossa função teste fazemos alguma operação qualquer, como print("teste") e logo em seguida executamos a closure que recebemos:

closure()

Veja como fica a chamada da função teste:

teste(closure: {
    print("closure executada")
})

Note que...

{ 
    print("closure executada") 
}

é justamente um bloco de código que não tem nenhum argumento e devolve Void, ou seja, satisfaz o tipo () -> Void.

Então, ao executar teste com essa closure, teremos:

teste executada
closure executada

Veja que mesmo passando o bloco de código na chamada da função teste, ele não foi executado até ser chamado dentro de teste! E essa é a grande sacada.

Existem diversas funções no iOS que permitem que sejam passados blocos de código (nossas closures) para serem executados ao término de um processamento. Por uma padronização, as funções que têm essa característica recebem as closures num argumento chamado completion ou completionHandler (no nosso exemplo, chamamos esse argumento de closure mesmo).

Explicação fantastica! Me ajudou mto, mto obrigado!