Em uma revisão de código, você provavelmente já ouviu: “Adicione final a esta classe”.
Parece apenas um hábito, mas entender o motivo muda sua forma de enxergar o código.
Em resumo, final declara: “Esta classe não será estendida por herança”. É uma única linha que melhora desempenho e estabilidade do design.
Hoje vamos organizar os verdadeiros motivos para adicionar final às classes Swift.
Afinal, o que é final?
final é uma palavra-chave que impede herança e sobrescrita.
Quando aparece antes de uma classe, nenhuma outra classe pode herdá-la.
Antes de um método ou propriedade, também pode impedir a sobrescrita apenas daquele membro.
final class Logger {
func log(_ msg: String) { print("[LOG] \(msg)") }
}
let logger = Logger()
logger.log("Pagamento concluído") // Imprimir: [LOG] Pagamento concluído
Se você tentar herdar de Logger escrevendo class FileLogger: Logger, ocorrerá um erro de compilação.
É como cravar: “Esta classe termina aqui”.
Por que final deixa o código mais rápido?
O primeiro motivo é o desempenho. O ponto central é o modo de despacho (dispatch).
Enquanto a herança estiver aberta, o compilador não sabe até o runtime qual método será chamado e precisa procurá-lo em uma tabela toda vez.
Isso é o despacho dinâmico. Primeiro, a tabela de métodos (vtable) de cada classe é consultada; depois, a chamada é feita.
Com final, porém, a situação muda.
Como nenhuma subclasse pode interferir, o compilador pode ter certeza: “esta chamada sempre é para este método”.
Assim, ele chama diretamente, sem consultar a tabela. Esse é o despacho estático.
Indo além, métodos curtos podem ser expandidos no próprio ponto de chamada por meio de inlining.
O custo de uma chamada não é alto, mas, se o método for executado milhares de vezes dentro de um loop, a diferença se acumula.
O verdadeiro motivo é o “design”, mais do que o desempenho
Na verdade, considero este ponto mais importante que o desempenho.
É a capacidade de evitar o problema da classe base frágil (fragile base class).
Ao deixar a herança aberta, qualquer pessoa pode interferir livremente no funcionamento interno da classe pai que você criou.
Basta alterar sem querer um método do pai para que os filhos que o sobrescreveram quebrem em sequência.
A herança é a relação que mais viola a encapsulação. O filho passa a enxergar até as entranhas do pai.
Por isso, os princípios de design orientado a objetos dizem o seguinte.
Projete e documente para herança. Caso contrário, proíba-a. Esse é o famoso conselho de Effective Java.
final é a ferramenta para colocar esse conselho em prática no código.
O compilador impõe a intenção: “não projetei para herança, então não vou deixar aberto”.
Com a intenção clara, os colegas também se perdem menos ao ler o código no futuro.
Então é obrigatório adicionar sempre?
Um ponto importante: em Swift, um tipo por referência não precisa ser necessariamente uma classe.
Se o estado puder ser tratado como valor, struct costuma ser uma escolha melhor. struct não possui herança desde o início.
Antes de pensar “devo adicionar final?”, pergunte primeiro: “isso realmente precisa ser uma classe?”.
Se ainda assim precisar usar uma classe, avalie pelos critérios abaixo.
| Situação | Decisão |
|---|---|
| Classe sem intenção de herança | Adicionar final (padrão) |
| Código com chamadas repetidas sensíveis a desempenho | Usar final para induzir despacho estático |
| Framework com pontos de extensão claramente projetados | Deixar a herança aberta |
| API que pressupõe herança, como UIViewController | Não adicionar |
É fácil lembrar assim.
- Se a herança não foi planejada, adicione final por padrão
- Abra apenas os pontos de extensão que você quiser oferecer
- Se puder ser struct, evite uma classe desde o início
Em entrevistas, a pergunta costuma ser assim
P. Quais são as vantagens de adicionar a palavra-chave final?
Impede herança e sobrescrita, deixando clara a intenção do design. Ao mesmo tempo, o compilador pode usar despacho estático em vez de dinâmico, reduzindo o custo das chamadas e permitindo a otimização por inlining.
P. Então devemos adicionar final a todas as classes?
Classes projetadas e documentadas para herança devem permanecer abertas. Sem essa intenção, é mais seguro fechá-las por padrão; se o significado de valor fizer sentido, considere primeiro usar struct.
Uma única linha com final não é apenas uma dica de otimização: ela responde a “como esta classe deve ser usada?”.
A partir de hoje, ao criar uma classe, pergunte: “existe algum motivo para deixar a herança aberta?”. Esse hábito tornará seu código muito mais sólido.

