Lembre-se também de que podem ocorrer ciclos de retenção se o seu bloco se referir a outro objeto que então retém self
.
Não tenho certeza de que a coleta de lixo possa ajudar nesses ciclos de retenção. Se o objeto que retém o bloco (que chamarei de objeto servidor) sobrevive self
(o objeto cliente), a referência aself
dentro do bloco não será considerada cíclica até que o próprio objeto retentor seja liberado. Se o objeto do servidor sobreviver a seus clientes, você pode ter um vazamento de memória significativo.
Como não há soluções limpas, eu recomendaria as seguintes soluções alternativas. Sinta-se à vontade para escolher um ou mais deles para corrigir seu problema.
- Use blocos apenas para conclusão , e não para eventos abertos. Por exemplo, use blocos para métodos como
doSomethingAndWhenDoneExecuteThisBlock:
, e não métodos comosetNotificationHandlerBlock:
. Os blocos usados para conclusão têm fins de vida definidos e devem ser liberados pelos objetos do servidor após serem avaliados. Isso impede que o ciclo de retenção viva por muito tempo, mesmo que ocorra.
- Faça aquela dança de referência fraca que você descreveu.
- Forneça um método para limpar seu objeto antes que ele seja lançado, que "desconecta" o objeto dos objetos do servidor que podem conter referências a ele; e chame esse método antes de chamar release no objeto. Embora esse método seja perfeitamente adequado se seu objeto tiver apenas um cliente (ou for um singleton em algum contexto), mas será quebrado se tiver vários clientes. Você está basicamente derrotando o mecanismo de contagem de retenção aqui; isso é semelhante a ligar em
dealloc
vez de release
.
Se você estiver escrevendo um objeto de servidor, use argumentos de bloco apenas para conclusão. Não aceite argumentos de bloco para retornos de chamada, como setEventHandlerBlock:
. Em vez disso, volte ao padrão clássico de delegação: crie um protocolo formal e anuncie um setEventDelegate:
método. Não retenha o delegado. Se você nem deseja criar um protocolo formal, aceite um seletor como retorno de chamada delegado.
E, por último, esse padrão deve tocar alarmes:
- (nulo) dealloc {
[myServerObject releaseCallbackBlocksForObject: self];
...
}
Se você está tentando desengatar os blocos que podem se referir self
de dentro dealloc
, já está com problemas. dealloc
nunca pode ser chamado devido ao ciclo de retenção causado pelas referências no bloco, o que significa que seu objeto simplesmente vazará até que o objeto do servidor seja desalocado.
self
proxiesthis
apenas para mudar as coisas. Em JavaScript, chamo meusthis
encerramentosself
, para que pareça agradável e equilibrado. :)