web-dev-qa-db-fra.com

Quand dois-je libérer des objets dans - (void) viewDidUnload plutôt que dans -dealloc?

À quoi sert la -(void)viewDidUnload?

Pourrais-je pas simplement tout relâcher dans -dealloc? Si la vue se déchargeait, -dealloc être appelé quand même?

103
Thanks

En plus de ce qui a déjà été indiqué, je voulais approfondir la logique derrière -viewDidUnload.

L'une des raisons les plus importantes de sa mise en œuvre est que les sous-classes UIViewController contiennent généralement également des références propriétaires à diverses sous-vues dans la hiérarchie des vues. Ces propriétés auraient pu être définies via IBOutlets lors du chargement à partir d'une nib, ou par programmation dans -loadView, par exemple.

La propriété supplémentaire des sous-vues par le UIViewController signifie que même lorsque sa vue est supprimée de la hiérarchie des vues et libérée pour économiser de la mémoire, à travers laquelle les sous-vues sont également libérées par la vue, elles ne seront pas réellement désallouées car le UIViewController lui-même contient également ses propres références de conservation en suspens à ces objets. La libération du UIViewController propriété supplémentaire de ces objets garantit qu'ils seront également désalloués pour libérer de la mémoire.

Les objets que vous libérez ici sont généralement recréés et redéfinis lorsque la vue UIViewController est re-loaded, à partir d'une Nib ou via une implémentation de -loadView.

Notez également que la propriété UIViewControllerview est nil au moment où cette méthode est appelée.

51
Sean Murphy

Comme le la documentation dit :

Il est appelé dans des conditions de faible mémoire lorsque le contrôleur de vue doit libérer sa vue et tous les objets associés à cette vue pour libérer de la mémoire.

Dans la même situation, dealloc n'est pas appelé . Cette méthode est uniquement disponible dans OS3 et supérieur. Faire face à la même situation dans l'iPhone OS 2.x était une vraie douleur!

Mise à jour de juillet 2015 : il convient de noter que viewDidUnload était déconseillé dans iOS 6 car "les vues ne sont plus purgées dans des conditions de faible mémoire et donc cette méthode n'est jamais appelée. " Donc, le conseil moderne est de ne pas s'en inquiéter et d'utiliser dealloc.

21
Stephen Darlington

En effet, vous définissez généralement le @property Comme "(nonatomic, retain)" et en tant que tel, le setter qui est créé pour vous libère l'objet actuel et conserve ensuite l'argument, c'est-à-dire.

self.property = nil;

... fait quelque chose comme:

[property release];
property = [nil retain];

Par conséquent, vous tuez deux oiseaux avec une pierre: gestion de la mémoire (libération de l'objet existant) et affectation du pointeur à zéro (car l'envoi de tout message à un pointeur nul renvoie zéro).

J'espère que cela pourra aider.

9
gazzaaa87

N'oubliez pas que viewDidUnload est une méthode dans le contrôleur de vue, pas dans la vue. La méthode view'sdealloc sera appelée lors du déchargement de la vue, mais la méthode view controllererdealloc ne pourra être appelée que plus tard.

Si vous recevez un avertissement de mémoire insuffisante et que votre vue ne s'affiche pas, ce qui se produira par exemple à chaque fois que vous utilisez un UIImagePickerController pour permettre à l'utilisateur de prendre une photo, votre vue sera déchargée et devra être rechargée après cela.

8
David Maymudes

Apple obsolète viewWillUnload, maintenant vous devez utiliser didReceiveMemoryWarning ou dealloc pour libérer vos objets.

Dans iOS 6, les méthodes viewWillUnload et viewDidUnload de UIViewController sont désormais obsolètes. Si vous utilisiez ces méthodes pour libérer des données, utilisez plutôt la méthode didReceiveMemoryWarning. Vous pouvez également utiliser cette méthode pour libérer des références à la vue du contrôleur de vue si elle n'est pas utilisée. Vous devez tester que la vue n'est pas dans une fenêtre avant de le faire.

6

Conclusion:

Les contrôleurs de vue ont une propriété de vue. En général, une pointe ou un morceau de code ajoute d'autres vues à cette vue. Cela se produit souvent dans une méthode -viewDidLoad, comme ceci:

- (void)viewDidLoad {
    [super viewDidLoad];
    [self createManyViewsAndAddThemToSelfDotView];
}

en outre, un fichier nib peut créer un bouton et l'ajouter à la vue du contrôleur de vue.

Sur iPhone OS 2.2, lorsque -didReceiveMemoryWarning a été invoqué depuis le système, vous avez dû libérer quelque chose pour libérer de la mémoire. Vous pouvez libérer la vue entière du contrôleur de vue si cela a du sens. Ou simplement de gros contenus gourmands en mémoire.

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}

Maintenant, dans le nouveau système d'exploitation 3.0, il existe une méthode -viewDidUnload, qui sera invoquée depuis le système lorsque la vue a été déchargée en raison d'une mémoire insuffisante (veuillez me corriger: quand exactement cela est-il appelé?)

-viewDidUnload est utilisé pour libérer tous les objets qui appartenaient à la fois au contrôleur de vue lui-même et à la vue. La raison: si un contrôleur de vue contient des références aux enfants de la vue, c'est-à-dire un bouton, les vues enfant référencées ne seront pas libérées, car leur nombre de rétentions est> = 1. Une fois libérées dans -viewDidUnload, elles peuvent être libérées de mémoire.

6
Thanks

Si le contrôleur de vue est extrait de la pile du contrôleur de navigation et n'est conservé nulle part ailleurs, il sera désalloué et dealloc sera appelé à la place de viewDidUnload. Vous devez libérer les vues créées dans loadView dans dealloc, mais il n'est pas nécessaire de définir les variables sur nil, car peu de temps après l'appel de dealloc, les variables n'existeront plus.

5
Colin

Vous pouvez libérer toutes les sous-vues auxquelles vous vous accrochez, par exemple cette UIImageView que vous avez conservée dans votre méthode loadView, ou mieux encore l'image qui était sur cette UIImageView.

3
drvdijk