Rappelez-vous également que des cycles de rétention peuvent se produire si votre bloc se réfère à un autre objet qui retient ensuite self
.
Je ne suis pas sûr que Garbage Collection puisse aider dans ces cycles de conservation. Si l'objet conservant le bloc (que j'appellerai l'objet serveur) survit self
(l'objet client), la référence à l' self
intérieur du bloc ne sera pas considérée comme cyclique jusqu'à ce que l'objet de rétention lui-même soit libéré. Si l'objet serveur survit de loin à ses clients, vous pouvez avoir une fuite de mémoire importante.
Puisqu'il n'y a pas de solutions propres, je recommanderais les solutions de contournement suivantes. N'hésitez pas à en choisir un ou plusieurs pour résoudre votre problème.
- Utilisez des blocs uniquement pour la finalisation , et non pour les événements ouverts. Par exemple, utilisez des blocs pour des méthodes comme
doSomethingAndWhenDoneExecuteThisBlock:
, et non des méthodes commesetNotificationHandlerBlock:
. Les blocs utilisés pour l'achèvement ont une fin de vie définie et doivent être libérés par les objets serveur après leur évaluation. Cela empêche le cycle de rétention de vivre trop longtemps même s'il se produit.
- Faites cette danse de référence faible que vous avez décrite.
- Fournissez une méthode pour nettoyer votre objet avant sa sortie, qui "déconnecte" l'objet des objets serveur qui peuvent lui contenir des références; et appelez cette méthode avant d'appeler release sur l'objet. Bien que cette méthode soit parfaitement adaptée si votre objet n'a qu'un seul client (ou est un singleton dans un certain contexte), elle s'effondrera s'il a plusieurs clients. Vous êtes en train de vaincre le mécanisme de comptage de retenue ici; cela revient à appeler
dealloc
au lieu de release
.
Si vous écrivez un objet serveur, ne prenez les arguments de bloc que pour terminer. N'acceptez pas les arguments de bloc pour les rappels, tels que setEventHandlerBlock:
. Au lieu de cela, revenez au modèle de délégué classique: créez un protocole formel et publiez une setEventDelegate:
méthode. Ne retenez pas le délégué. Si vous ne souhaitez même pas créer de protocole formel, acceptez un sélecteur comme rappel de délégué.
Et enfin, ce modèle devrait sonner des alarmes:
- (void) dealloc {
[myServerObject releaseCallbackBlocksForObject: self];
...
}
Si vous essayez de décrocher des blocs qui peuvent faire référence self
de l'intérieur dealloc
, vous avez déjà des problèmes. dealloc
peut ne jamais être appelé en raison du cycle de rétention causé par les références dans le bloc, ce qui signifie que votre objet va simplement fuir jusqu'à ce que l'objet serveur soit désalloué.
self
mandatairesthis
juste pour inverser les choses. En JavaScript, j'appelle mesthis
fermeturesself
, donc c'est agréable et équilibré. :)