weak
as referências parecem não funcionar no Swift, a menos que a protocol
seja declarado como @objc
, o que não desejo em um aplicativo Swift puro.
Este código fornece um erro de compilação ( weak
não pode ser aplicado ao tipo que não é de classe MyClassDelegate
):
class MyClass {
weak var delegate: MyClassDelegate?
}
protocol MyClassDelegate {
}
Preciso prefixar o protocolo com @objc
, então ele funciona.
Pergunta: Qual é a maneira rápida 'pura' de realizar um weak
delegate
?
Respostas:
Você precisa declarar o tipo do protocolo como
AnyObject
.Usando
AnyObject
você, você diz que apenas classes podem estar em conformidade com este protocolo, enquanto estruturas ou enumerações não.fonte
protocol ProtocolNameDelegate: AnyObject
, mas não importa.AnyObject
porqueclass
será descontinuado em algum momento.Resposta complementar
Sempre fiquei confuso sobre se os delegados deveriam ser fracos ou não. Recentemente, aprendi mais sobre os delegados e quando usar referências fracas, então deixe-me acrescentar alguns pontos adicionais aqui para o bem dos futuros telespectadores.
O objetivo do uso da
weak
palavra-chave é evitar ciclos de referência fortes (ciclos de retenção). Ciclos de referência fortes acontecem quando duas instâncias de classe têm referências fortes uma à outra. Suas contagens de referência nunca chegam a zero e nunca são desalocadas.Você só precisa usar
weak
se o delegado for uma classe. Estruturas e enumerações rápidas são tipos de valor (seus valores são copiados quando uma nova instância é criada), não tipos de referência, portanto, eles não fazem ciclos de referência fortes .weak
as referências são sempre opcionais (caso contrário você usariaunowned
) e semprevar
(nãolet
) para que o opcional possa ser definido comonil
quando for desalocado.Uma classe pai deve naturalmente ter uma forte referência a suas classes filho e, portanto, não usar a
weak
palavra - chave. Porém, quando uma criança deseja uma referência ao pai, ela deve ser uma referência fraca usando aweak
palavra - chave.weak
deve ser usado quando você quiser uma referência a uma classe que não é sua, não apenas para um filho que faz referência ao pai. Quando duas classes não hierárquicas precisam fazer referência uma à outra, escolha uma para ser fraca. O que você escolher depende da situação. Veja as respostas a esta pergunta para mais informações.Como regra geral, os delegados devem ser marcados como
weak
porque a maioria dos delegados está referenciando classes que não são de sua propriedade. Definitivamente, isso é verdade quando uma criança está usando um delegado para se comunicar com os pais. Usar uma referência fraca para o delegado é o que a documentação recomenda. (Mas veja isso também.)Os protocolos podem ser usados para os tipos de referência (classes) e tipos de valor (estruturas, enumerações). Portanto, no provável caso de você precisar tornar um delegado fraco, é necessário torná-lo um protocolo somente de objeto. A maneira de fazer isso é adicionar
AnyObject
à lista de herança do protocolo. (No passado, você fazia isso usando aclass
palavra - chave, masAnyObject
é preferível agora .)Um estudo mais aprofundado
A leitura dos artigos a seguir foi o que me ajudou a entender isso muito melhor. Eles também discutem questões relacionadas, como a
unowned
palavra - chave e os fortes ciclos de referência que acontecem com os fechamentos.Relacionado
fonte
AnyObject
é a maneira oficial de usar uma referência fraca no Swift.Da Apple:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html#//apple_ref/doc/uid/TP40014097-CH25-ID276
fonte
class
descontinuado no Swift 4.1?Atualização: parece que o manual foi atualizado e o exemplo ao qual eu estava me referindo foi removido. Veja a edição da resposta de @ flainez acima.
Original: usar @objc é a maneira certa de fazê-lo, mesmo que você não esteja interagindo com o Obj-C. Isso garante que seu protocolo esteja sendo aplicado a uma classe e não a uma enumeração ou estrutura. Consulte "Verificando a conformidade do protocolo" no manual.
fonte
O protocolo deve ser subclasse de AnyObject, classe
exemplo dado abaixo
fonte
A Apple usa "NSObjectProtocol" em vez de "classe".
Isso também funciona para mim e removeu os erros que eu estava vendo ao tentar implementar meu próprio padrão de delegado.
fonte