Referências fracas a protocolos em Swift sem @objc: guia completo

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Como fazer uma referência fraca a um protocolo em Swift puro (sem @objc)? Guia completo com exemplos

\n\n

Imagine: você está escrevendo um aplicativo em Swift, usando o padrão Delegate, e de repente — bum! — seus objetos não são destruídos, a memória cresce e o aplicativo começa a travar. Familiar? Provavelmente, você se deparou com um retain cycle (ciclo de referências fortes). Um problema clássico quando o delegado mantém uma referência forte ao proprietário, e o proprietário mantém uma referência forte ao delegado. A solução que vem à mente primeiro é tornar a referência ao protocolo fraca (weak). Mas aqui o Swift prega uma peça: você não pode simplesmente declarar weak var delegate: MyProtocol se o protocolo não estiver marcado com @objc. O compilador emitirá um erro. Por quê? E o principal — como contornar isso?

\n\n

Neste artigo, vamos explorar como fazer weak protocol reference em Swift puro sem @objc. Você aprenderá por que isso é um problema, quais são as soluções e como escrever um código bonito e seguro, sem vazamentos de memória. Vamos lá!

\n\n

Por que weak protocol reference não funciona "de fábrica"?

\n\n

Vamos lembrar como o weak funciona em Swift. Uma referência fraca (weak) só pode existir para reference types (classes). Por quê? Porque apenas objetos de classes têm gerenciamento de memória via ARC (Automatic Reference Counting). Structs (struct) e enums (enum) são value types, eles são copiados, e para eles o conceito de "referência fraca" não faz sentido.

\n\n

Quando você escreve:

\n
weak var delegate: MyProtocol?
\n

O compilador não sabe se MyProtocol será implementado por uma classe, struct ou enum. E se for uma struct? Então weak não pode ser aplicado. Daí o erro: «'weak' may only be applied to class and class-bound protocol types».

\n\n

Antigamente (em Objective-C), todos os protocolos por padrão só podiam ser implementados por classes, então weak funcionava. Em Swift puro, os protocolos são universais — e isso é ótimo, mas adiciona complexidades.

\n\n

Solução nº 1: class-bound protocol (protocolo restrito a classes)

\n\n

A maneira mais simples e comum é especificar explicitamente que o protocolo pode ser implementado apenas por classes. Para isso, usa-se a palavra-chave AnyObject (ou a obsoleta class) na declaração do protocolo.

\n\n

Exemplo:

\n
protocol MyDelegate: AnyObject {\n    func didSomething()\n}\n\nclass ViewController {\n    weak var delegate: MyDelegate?\n\n    func doSomething() {\n        delegate?.didSomething()\n    }\n}\n\nclass SomeClass: MyDelegate {\n    func didSomething() {\n        print("Delegado acionado!")\n    }\n}\n\n// Uso\nlet vc = ViewController()\nlet some = SomeClass()\nvc.delegate = some\nvc.doSomething() // Exibirá: "Delegado acionado!"
\n\n

Tudo funciona. MyDelegate agora só pode ser implementado por uma classe (class), e weak é legal. Esta é a abordagem recomendada pela Apple para delegados.

\n\n

Por que isso é bom?

\n
    \n
  • Simplicidade e legibilidade.
  • \n
  • Suporte total ao ARC.
  • \n
  • Não há necessidade de @objc.
  • \n
\n\n

Desvantagens?

\n
    \n
  • Você perde a possibilidade de implementar o protocolo com uma struct. Mas para delegados, isso geralmente não é necessário.
  • \n
\n\n

Solução nº 2: Uso de generic wrapper (para casos exóticos)

\n\n

E se você precisar permitir que o protocolo seja implementado tanto por classes quanto por structs, mas ainda assim quiser uma referência fraca? Isso é raro, mas possível. Por exemplo, você está escrevendo uma biblioteca onde o usuário pode passar tanto uma classe quanto uma struct. Nesse caso, um wrapper pode ajudar.

\n\n

A ideia: criar uma struct que armazena uma referência fraca ao objeto que implementa o protocolo. Para classes — we

Blogs

Book Recommendations