Je navigue sur le merveilleux blog maintenu par Scott Stevenson et j'essaie de comprendre un concept fondamental d'Objective-C consistant à affecter aux délégués la propriété "attribuer" ou "conserver". Notez que les deux sont les mêmes dans un environnement de récupération. Je suis principalement concerné par un environnement non basé sur le GC (par exemple: iPhone).
Directement à partir du blog de Scott:
"Le mot-clé assign génèrera un séparateur qui assignera directement la valeur à la variable d'instance, plutôt que de la copier ou de la conserver. C'est le meilleur choix pour les types primitifs tels que NSInteger et CGFloat, ou les objets que vous ne possédez pas directement, tels que les délégués."
Qu'est-ce que cela signifie que vous ne possédez pas directement l'objet délégué? Je retiens généralement mes délégués, parce que si je ne veux pas qu'ils s'en aillent dans l'abîme, rétention s'en chargera pour moi. J'abstiens généralement UITableViewController loin de son source de données et le délègue également. Je conserve également cet objet particulier. Je veux m'assurer qu'il ne s'en ira jamais afin que mon UITableView ait toujours son délégué autour.
Quelqu'un peut-il expliquer davantage où/pourquoi je me trompe afin que je puisse comprendre ce paradigme commun à la programmation Objective-C 2.0 consistant à utiliser la propriété assign sur les délégués au lieu de conserver?
Merci!
La raison pour laquelle vous évitez de conserver des délégués est que vous devez éviter un cycle de conservation:
A crée B A se définit comme délégué de B… A est libéré par son propriétaire
Si B avait conservé A, A ne serait pas libéré, car B en possède, ainsi le dealloc de A ne serait jamais appelé, ce qui provoquerait une fuite de A et B.
Vous ne devriez pas vous inquiéter de la disparition de A, car elle possède B et l’élimine ainsi dans dealloc.
Parce que l'objet qui envoie les messages de délégué ne possède pas le délégué.
Souvent, c'est l'inverse qui se produit, par exemple lorsqu'un contrôleur se définit comme le délégué d'une vue ou d'une fenêtre: le contrôleur est propriétaire de la vue/fenêtre. Ainsi, si la vue/fenêtre appartenait à son délégué, les deux objets se possédaient mutuellement. Ceci est bien sûr un cycle de rétention, similaire à une fuite ayant la même conséquence (les objets qui devraient être morts restent en vie).
D'autres fois, les objets sont des pairs: aucun des deux ne possède l'autre, probablement parce qu'ils appartiennent tous les deux au même troisième objet.
Dans les deux cas, l'objet avec le délégué ne doit pas conserver son délégué.
(Il y a au moins une exception, en passant. Je ne me souviens pas de quoi il s'agissait, et je ne pensais pas qu'il y avait une bonne raison pour cela.)
Addendum (ajouté le 2012-05-19): Sous ARC, vous devez utiliser weak
au lieu de assign
. Les références faibles sont définies automatiquement sur nil
lorsque l'objet meurt, ce qui élimine la possibilité que l'objet délégué envoie des messages au délégué mort.
Si vous vous éloignez d'ARC pour une raison quelconque, changez au moins les propriétés assign
qui pointent vers les objets en unsafe_unretained
, qui expliquent qu'il s'agit d'une référence à un objet non conservée mais non remise à zéro.
assign
reste approprié pour les valeurs non-objets sous ARC et MRC.
Notez que lorsque vous avez un délégué qui est assigné, il est très important de toujours définir cette valeur de délégué sur nil chaque fois que l'objet va être désalloué. Ainsi, un objet doit toujours veiller à supprimer les références de délégué dans dealloc s'il ne l'a pas déjà été. fait tellement ailleurs.
Une des raisons derrière cela est d'éviter les cycles de rétention. Juste pour éviter le scénario où les objets A et B se référencent et qu'aucun d'entre eux n'est libéré de la mémoire.
En réalité, assign convient aux types primitifs tels que NSInteger et CGFloat, ou aux objets que vous ne possédez pas directement, tels que les délégués.