Protocolos em Swift: Quando e como utilizar
Tags: swift, ios, programming, mobile
Published: 2021-10-27 15:39:12

Fala dev! Se você começou no Swift ou em programação recentemente já deve ter se perguntado qual a diferença entre Classes, Structs e Protocolos. A primeira vista eles podem parecer iguais e dar a impressão de que têm a mesma finalidade, principalmente quando comparamos Classes com Structs. Apesar de serem parecidas, essas estruturas de dados tem finalidades diferentes! Esse é o primeiro artigo de três, e nele eu vou falar sobre Protocolos!

### Sobre a nossa didática

Ao invés de usar exemplos comuns de código com estruturas chamadas `Pessoa` ou `Animal`, chamaremos nossas estruturas de `Foguete`! Vamos para o código.

### Protocols

Os **protocolos são formatos de dados que você pode construir para ter uma estrutura personalizada que armazena e padroniza objetos**. Eles apenas ditam quais propriedades, métodos ou construtores uma Classe ou Struct deve ter, mas **sem implementa-los!** Vamos ver um exemplo:

Imagine que o INPE (Instituto Nacional de Pesquisas Espaciais) precisa salvar todos os projetos de seus foguetes. Cada um deles segue um protocolo de segurança, deve ser transportado e possui um jeito específico de ser lançado, além de ter seus devidos tripulantes, isto é, todos possuem esses métodos e propriedades, mas a implementação e conteúdo deles é sempre diferente. Você poderia pensar "Ora, vamos criar uma classe para cada um", mas sair declarando um monte de classes deliberadamente talvez não seja a melhor solução.

Vamos criar um protocolo chamado `Foguete` e definir nele as características das nossas naves espaciais:

```swift
protocol Foguete {

    static var tripulantes: List<String>

    init(tripulantes: List<String>)

    static func verificarSeguranca()
    static func transportar()
    static func decolar()
}
```

Muito bem, agora nós temos um padrão de construção de objetos `Foguete` que pode ser usado para a criação de classes, basta conformar com ele:

```swift
class FogueteAurora: Foguete {

    var tripulantes: List<String>

    //init do FogueteAurora
    init(tripulantes: List<String>) {
        self.tripulantes = tripulantes
    }

    // verificarSeguranca do FogueteAurora
    func verificarSeguranca() {
        verificarMotores()
    }

    // transportar do FogueteAurora
    func transportar() {
        transportarNoCaminhao()
    }

    // decolar do FogueteAurora
    static func decolar() {
        ligarMotores()
        soltarDaPlataforma()
    }
}
```

Note os comentários do código. Eles se referem às implementações desse foguete em específico, se alguma outra classe conformar com o nosso protocolo ela poderá implementar os mesmos métodos, mas do jeito que necessita, sem interferir ou ao menos saber sobre a implementação do `FogueteAurora`!

Agora você deve estar perguntando "Mas você não disse que criar classes não era uma boa abordagem?". A questão não é criar muitas ou poucas classes, e sim criar classes padronizadas! Com a existência do protocolo todos os foguetes tem implementações dos mesmos métodos e propriedades, mas elas não são necessariamente iguais! E se algum objeto não seguir essa estrutura, não pode ser considerado um objeto do tipo `Foguete`.

> Tendo um protocolo para a criação de objetos eu posso ter certeza de que se receber um objeto que conforma com o protocolo X esse item vai ter as características de X! Além disso, fica bem mais fácil criar funções que manipulem objetos com essa estrutura, já que agora você tem uma estrutura de dados para usar como tipo.

Vamos ver isso na prática: agora imagine que o INPE queira simular a execução das funções do foguetes com uma outra função. Como faríamos isso se apenas tivéssemos um monte classes? Teríamos que pegar uma por uma, verificar se existem todos os métodos necessários e então executa-los. Isso parece trabalhoso, não? Vamos usar o nosso protocolo e criar uma função assim:

```swift
func executarFuncoesDoFoguete(foguete: Foguete) {
    foguete.varificarSeguranca()
    foguete.transportar()
    foguete.decolar()
}
```

Recebemos por parâmetro uma variável do tipo `Foguete`, que é o nosso protocolo, assim nós sempre temos certeza de que os métodos que estamos chamando dentro da nossa função existem, mesmo que estejam vazios! No caso de estarem vazios nada acontece, mas se não existissem e tentássemos executa-los teríamos um erro… e eu acho que prefiro a primeira opção, embora uma situação dessa fira o conceito de Interface Segregation do SOLID, mas isso é assunto pra outro artigo.

Pronto, agora basta chamar a função passando para ela um objeto que conforme com Foguete, como o `FogueteAurora`!

### Quando usar Protocolos?
Quando você tem uma estrutura de dados que precisa ser declarada, mas sua implementação nem sempre será igual.

---

Espero ter ajudado a organizar suas ideias, nos vemos na próxima! 😄

---

Referências
Protocols - The Swift Programming Language (Swift 5.4): https://docs.swift.org/swift-book/LanguageGuide/Protocols.html