33 votes

Objective C : Release, Dealloc, et la référence Self

Donc je pensais avoir répondu à toutes ces questions. Puis, tout d'un coup, j'ai une erreur (un crash) que je n'arrive pas à comprendre. Après avoir effectué des recherches pour remédier au problème, je me rends compte que tout ce que je pensais savoir sur ces domaines critiques était faux.

Voici 8 questions que je vais lancer dans l'espoir que quelqu'un y réponde - les réponses à ces questions m'aideront grandement à remettre ma compréhension sur les rails. Merci d'avance !

Q1) Est-il possible d'appeler Release sur un objet si cette référence est nulle ? Cela devrait être inoffensif, non ?

Q2) Est-il possible d'appeler Release sur un objet si la référence a été libérée et que le nombre de références est de 0 ?

Q3) Est-il nécessaire de mettre une référence à zéro APRÈS l'avoir libérée ? Que se passe-t-il si on ne lui donne pas la valeur nil ?

Q4) Y a-t-il vraiment une différence entre nil et NULL, ou est-ce juste une question de sémantique pour aider le lecteur/développeur à connaître le type d'objet juste en le regardant ?

Q5) L'utilisation des propriétés nécessite-t-elle l'utilisation du pointeur "Self" ?

Q6) L'utilisation de variables d'instance nécessite que le pointeur 'Self' ne soit PAS utilisé ?

Q7) Quand voudrais-je utiliser une variable d'instance au lieu de sa propriété ? J'imagine que les membres de données de type valeur sont acceptables puisqu'il n'y a pas de libération et de conservation en jeu.

Q8) Est-il nécessaire d'appeler la fonction dealloc d'un objet à partir de la fonction dealloc ? Dans de nombreux exemples, j'ai vu la fonction Release être appelée, mais pas la fonction Dealloc - de tels tutoriels sont-ils incorrects ?

19voto

Tom Dalling Points 10656

A1) [nil release] est bien (ne fait rien)

A2) Non. Ne touchez pas aux objets après qu'ils aient été désalloués. Ils doivent être mis à nil après avoir été libérés.

A3) Il n'est pas nécessaire de mettre un pointeur libéré à nil, mais vous obtenez des pointeurs pendants (c'est-à-dire que vous ne pouvez pas dire si un objet est valide ou non). Mettre une propriété à nil est souvent utilisé pour libérer l'ivar sous-jacent, donc ne pas le faire peut causer une fuite de mémoire.

A4) nil et NULL sont tous deux égaux à zéro, et sont donc techniquement identiques.

A5) Oui, vous devez utiliser self.someProperty pour les propriétés, tout comme vous utiliseriez [self someProperty] si c'était juste une méthode

A6) self est essentiellement un struct, donc vous pouvez accéder aux ivars comme suit : self->someIvar . Mais ce n'est pas nécessaire.

A7) Lorsque vous ne voulez pas exécuter les méthodes setter/getter pour une raison quelconque. Je l'utilise occasionnellement lorsque le setter n'autorise pas les valeurs nil et que je dois libérer la variable.

A8) dealloc est appelé automatiquement lorsque release est appelé le nombre correct de fois. Vous ne devez jamais appeler dealloc directement (sauf pour [super dealloc]).

11voto

kperryua Points 6905

Vous auriez probablement dû diviser cette question en plusieurs questions différentes, mais je vais mordre.

  1. Oui, tout message envoyé à nil est un no-op.
  2. Non. Un objet avec un ref-count de 0 a été, ou sera bientôt, détruit et tout message qui lui sera envoyé provoquera un crash, ou au mieux, une exception.
  3. Cela dépend de la situation. Si vous publiez des choses dans -dealloc alors probablement pas. S'il s'agit d'un objet dont la portée est limitée à une méthode particulière, alors probablement pas. Si c'est un ivar qui est réutilisé, je dirais oui. Dans les deux premiers cas, rien ne se passera si vous ne mettez pas les pointeurs à nil, puisque vous ne pourrez généralement plus accéder à ces pointeurs. Dans le dernier cas, cependant, vous pouvez toujours accéder au pointeur, qui pointe vers la mémoire désallouée. Si vous lui envoyez un message ou essayez de le déréférencer, votre application se plantera.
  4. Ils sont tous deux égaux à 0. Par convention nil est utilisé pour les pointeurs d'objets, et NULL est utilisé pour tout autre pointeur, mais les mélanger ne posera aucun problème.
  5. Si vous voulez invoquer le getter/setter de la propriété, alors oui. Si vous voulez accéder directement à l'ivar qu'il encapsule (peu courant), non.
  6. Non, vous pouvez accéder aux variables d'instance en utilisant la syntaxe suivante self->ivar . En fait, lorsque vous tapez juste ivar le compilateur ajoute implicitement l'élément self-> déréférencement.
  7. Je ne suis pas sûr de ce que vous voulez dire ici.
  8. Le seul moment où vous devriez appeler -dealloc c'est lorsqu'on appelle [super dealloc]; dans votre propre -dealloc méthodes. Pour tout autre objet, vous devez toujours appeler -release .

8voto

Peter N Lewis Points 12025

D'autres ont répondu de manière adéquate aux questions 1 à 6.

(7) Apple recommande d'utiliser la variable d'instance directement dans vos init et dealloc. C'est principalement parce que l'objet (surtout s'il est sous-classé) n'est que partiellement configuré pendant ces deux méthodes, et donc l'appel des setters/getters peut résulter en un comportement incorrect s'ils ont autre chose que des actions triviales. En général, vous pouvez accéder à l'ivar directement (plutôt que via le getter) dans votre objet, et il sera légèrement plus efficace de le faire (uniquement pertinent sur l'iPhone). En général, vous devriez utiliser le setter dans tous les cas, surtout si votre objet peut être sous-classé ou si d'autres personnes peuvent observer la propriété.

(8) Vous n'appelez jamais, jamais, dealloc (sauf [super dealloc] à l'intérieur de la méthode dealloc). Si vous êtes propriétaire d'un autre objet, vous devez renoncer à cette propriété (en appelant release ou autorelease). Le système appellera alors dealloc sur l'objet si nécessaire. Mais vous ne devez jamais appeler dealloc vous-même. Lisez le règles de gestion de la mémoire (elle ne comporte que 9 paragraphes et il est essentiel de la comprendre).

0voto

Edward An Points 529

Ok. J'ai confirmé que le fait de ne pas mettre B à nil a fait l'affaire. Donc, maintenant, je ne vérifie pas la présence de nil lors de la création du contrôleur B (lorsque je veux y naviguer).

Au lieu de cela, je libère B, puis je crée le contrôleur et l'assigne à B. Ensuite, dans la méthode viewDidAppear de A, je libère B.

Je crois que ce fil est maintenant fermé. Merci !

0voto

A4) Ils diffèrent par leurs types. Ils sont tous de type zéro, mais NULL est un void *, nil est un id, et Nil est un pointeur de classe.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X