Dois-je définir les propriétés sur nil dans dealloc lors de l'utilisation d'ARC?

125

J'essaie d'apprendre le comptage automatique des références dans iOS 5. La première partie de cette question devrait maintenant être simple:

  1. Est-il correct que je n'ai PAS besoin d'écrire des déclarations de propriété de libération explicites dans mon dealloc lorsque j'utilise ARC? En d'autres termes, est-il vrai que ce qui suit n'a PAS besoin d'un dealloc explicite?

    @interface MyClass : NSObject
    @property (strong, nonatomic) NSObject* myProperty;
    @end
    
    @implementation MyClass
    @synthesize myProperty;
    @end
  2. Ma question suivante et la plus importante vient d'une ligne du document Transitioning to ARC Release Notes :

    Vous n'avez pas à (en effet pas) libérer les variables d'instance, mais vous devrez peut-être invoquer [self setDelegate: nil] sur les classes système et tout autre code qui n'est pas compilé à l'aide d'ARC.

    Cela soulève la question: comment savoir quelles classes système ne sont pas compilées avec ARC? Quand dois-je créer mon propre dealloc et définir explicitement les propriétés conservant fortement la valeur nulle? Dois-je supposer que toutes les classes de framework NS et UI utilisées dans les propriétés nécessitent des deallocs explicites?

Il existe une mine d'informations sur le SO et ailleurs sur les pratiques de libération de l'ivar de soutien d'une propriété lors de l'utilisation du suivi manuel des références, mais relativement peu à ce sujet lors de l'utilisation de l'ARC.

emfurry
la source

Réponses:

197

Réponse courte : non, vous n'êtes pas obligé de supprimer des propriétés deallocsous ARC.

Réponse longue : vous ne devriez jamais supprimer de propriétés dealloc, même dans la gestion manuelle de la mémoire.

Dans MRR, vous devez libérer vos ivars . Supprimer les propriétés signifie appeler des setters, ce qui peut invoquer du code qu'il ne devrait pas toucher dealloc(par exemple si votre classe, ou une sous-classe, remplace le setter). De même, il peut déclencher des notifications KVO. La libération de l'ivar évite plutôt ces comportements indésirables.

Dans ARC, le système libère automatiquement tous les ivars pour vous, donc si c'est tout ce que vous faites, vous n'avez même pas à implémenter dealloc. Cependant, si vous avez des ivars non-objets qui nécessitent un traitement spécial (par exemple des tampons alloués dont vous avez besoin free()), vous devez toujours les gérer dans dealloc.

De plus, si vous vous êtes défini comme délégué de tout objet, vous devez désactiver cette relation dans dealloc(c'est le peu sur l'appel [obj setDelegate:nil]). La note sur le fait de faire cela sur les classes qui ne sont pas compilées avec ARC est un clin d'œil aux propriétés faibles. Si la classe marque explicitement sa delegatepropriété comme, weakvous n'êtes pas obligé de le faire, car la nature des propriétés faibles signifie qu'elle sera supprimée pour vous. Cependant, si la propriété est marquée, assignvous devez la supprimer dans votre dealloc, sinon la classe est laissée avec un pointeur suspendu et se plantera probablement si elle essaie d'envoyer un message à son délégué. Notez que cela s'applique uniquement aux relations non conservées, telles que les délégués.

Lily Ballard
la source
2
C'est logique! Permettez-moi de vous demander ceci cependant: un scénario courant que j'ai est que j'ai une MyController : UIViewControllerclasse qui crée et possède un UIView et définit également le délégué de la vue à lui-même. Il est le seul propriétaire de ce point de vue. Lorsque le contrôleur est libéré, la vue doit également être libérée. Est-il alors important que le pointeur du délégué soit suspendu?
emfurry
4
@emfurry: Ce n'est probablement pas le cas, car au moment où votre contrôleur de vue meurt, la vue elle-même ne devrait pas être dans la hiérarchie des vues et ne devrait rien faire, mais il vaut mieux ne pas faire d'hypothèses. Que se passe-t-il si la vue planifiée de manière asynchrone doit être effectuée plus tard et que la vue elle-même finit par survivre à son contrôleur de vue pendant un court laps de temps (par exemple en raison du travail asynchrone conservant temporairement la vue)? Il est préférable de supprimer simplement le délégué pour être en sécurité. Et en fait, si la vue en question est a UIWebView, la documentation indique explicitement que vous devez supprimer le délégué.
Lily Ballard
3
@zeiteisen: Non, unsafe_unretainedc'est exactement l'équivalent d'une assignpropriété et c'est le comportement normal pour les relations de délégué sous MRR, et celles-ci doivent être supprimées.
Lily Ballard
4
Je ne suis pas d'accord avec la déclaration de ne pas utiliser de setters dans dealloc avec MRC. Apple ne le recommande pas, mais ils le font également dans leur code. Vous pouvez créer de nouveaux problèmes en n'utilisant pas le setter. Il y a plusieurs grandes discussions à ce sujet. Ce qui est important, c'est d'écrire correctement le setter (il doit se comporter correctement si vous lui passez une valeur nulle) et parfois de surveiller l'ordre de désallocation.
Sulthan
7
@Sulthan: Utiliser ou non des setters dans dealloc est une énorme boîte de vers, mais ma position se résume essentiellement à: vous voulez appeler le moins de code possible dans dealloc. Les setters ont tendance à inclure des effets secondaires, soit en remplaçant dans les sous-classes, soit via KVO, ou d'autres mécanismes. Les effets secondaires de dealloc doivent être évités en particulier comme la peste. Si vous pouvez éventuellement supprimer un appel de méthode de dealloc, vous devez le faire. Ceci est simplifié à: n'appelez pas les setters dans dealloc.
Lily Ballard
2

Juste pour donner la réponse opposée ...

Réponse courte : non, vous n'avez pas à supprimer les propriétés auto-synthétisées deallocsous ARC. Et vous n'avez pas besoin d'utiliser le setter pour ceux qui sont en init.

Réponse longue : vous ne devriez pas supprimer les propriétés synthétisées sur mesure dealloc, même sous ARC. Et vous devriez utiliser le setter pour ceux en init.

Le fait est que vos propriétés synthétisées personnalisées doivent être sûres et symétriques en ce qui concerne l'annulation.

Un poseur possible pour une minuterie:

-(void)setTimer:(NSTimer *)timer
{
    if (timer == _timer)
        return;

    [timer retain];
    [_timer invalidate];
    [_timer release];
    _timer = timer;
    [_timer fire];
}

Un setter possible pour un scrollview, tableview, webview, textfield, ...:

-(void)setScrollView:(UIScrollView *)scrollView
{
    if (scrollView == _scrollView)
        return;

    [scrollView retain];
    [_scrollView setDelegate:nil];
    [_scrollView release];
    _scrollView = scrollView;
    [_scrollView setDelegate:self];
}

Un poseur possible pour une propriété KVO:

-(void)setButton:(UIButton *)button
{
    if (button == _button)
        return;

    [button retain];
    [_button removeObserver:self forKeyPath:@"tintColor"];
    [_button release];
    _button = button;
    [_button addObserver:self forKeyPath:@"tintColor" options:(NSKeyValueObservingOptions)0 context:NULL];
}

Ensuite , vous ne devez pas dupliquer tout code dealloc, didReceiveMemoryWarning, viewDidUnload, ... et votre propriété peut être rendue publique en toute sécurité. Si vous vous inquiétez de l'absence de propriétés dealloc, il est peut-être temps de vérifier à nouveau vos setters.

Cœur
la source