Sobes.tech
Middle+

O que viola a função opcional no protocolo?

sobes.tech IA

Resposta da IA

Adicionar requisitos ao protocolo após outros módulos ou bibliotecas já terem começado a usá-lo. Se o protocolo já foi aceite e implementado, adicionar métodos ou propriedades opcionais (não obrigatórios) causará erros de compilação em todos os locais onde o protocolo é utilizado, até que esses novos requisitos sejam cumpridos.

Requisitos opcionais permitem expandir os protocolos sem "quebrar" as implementações existentes. Classes ou estruturas podem implementar apenas parte dos métodos opcionais. Isto é útil ao trabalhar com delegados ou ao adicionar novas funções a uma API já estabelecida.

Exemplo de requisito opcional em um protocolo em Objective-C (pois Swift não suporta @optional sem @objc) :

// Em Swift, `@optional` é usado com `@objc protocol`
import Foundation

@objc protocol MyDelegate {
    func requiredMethod() -> Bool

    @optional func optionalMethod1()
    @optional func optionalMethod2(value: Int)
}

class MyClass {
    weak var delegate: MyDelegate?

    func doSomething() {
        if delegate?.requiredMethod() == true {
            // Chamada de método opcional com verificação
            delegate?.optionalMethod1?()

            if let delegate = delegate {
                if delegate.responds(to: #selector(delegate.optionalMethod2(value:))) {
                    delegate.optionalMethod2?(value: 10)
                }
            }
        }
    }
}

Em Swift, protocolos puros (sem @objc) não suportam @optional. Para ter requisitos opcionais, o protocolo deve ser marcado como @objc. Implementações desses protocolos podem usar extensões para adicionar implementações padrão de métodos opcionais, o que é uma abordagem mais moderna em Swift.

Exemplo de comportamento opcional através de extensões de protocolos em Swift:

// Abordagem mais Swift: extensões de protocolos com implementação padrão
protocol MyProtocol {
    func requiredMethod() -> Bool
    func optionalMethod1()
    func optionalMethod2(value: Int)
}

// Fornecendo implementações padrão para métodos "opcionais"
extension MyProtocol {
    func optionalMethod1() {
        // Implementação padrão vazia ou comportamento padrão
        print("Implementação padrão do método opcional 1")
    }

    func optionalMethod2(value: Int) {
        // Implementação padrão vazia
        print("Implementação padrão do método opcional 2 com valor: \(value)")
    }
}

class MyClassSwift {
    var delegate: MyProtocol?

    func doSomething() {
        if delegate?.requiredMethod() == true {
            // Chamando métodos sem verificação de nil, pois
            // eles são ou implementados na classe/estrutura, ou usam
            // a implementação da extensão
            delegate?.optionalMethod1()
            delegate?.optionalMethod2(value: 20)
        }
    }
}

class MyCustomDelegate: MyProtocol {
    func requiredMethod() -> Bool {
        print("Método obrigatório implementado")
        return true
    }

    // optionalMethod1() e optionalMethod2(value:) não são obrigatórios de implementar,
    // será usada a implementação padrão da extensão.
    // Mas podem ser sobrescritos, se desejar outro comportamento:
    // func optionalMethod1() {
    //     print("Implementação personalizada do método opcional 1")
    // }
}

let customDelegate = MyCustomDelegate()
let myClassSwift = MyClassSwift()
myClassSwift.delegate = customDelegate
myClassSwift.doSomething()

Dessa forma, adicionar uma função opcional em um protocolo viola a compatibilidade retroativa ao tentar adicionar uma nova exigência obrigatória a um protocolo já em uso na base de código. O uso de requisitos opcionais (via @objc ou, preferencialmente, via extensões de protocolos) previne essa violação.