2009-04-30 3 views
7

Quelque part, je lisais que - en ce qui concerne les avertissements peu de mémoire et de renoncer à une vue non visible avec toutes ses sous-vues (= une pointe tout, je pense), vous devriez le faire:Pourquoi devrais-je écrire [version anView], anView = nil; plutôt que [version anView] ;?

-(void)dealloc { 
    [anView release], anView = nil; 
    [someImageView release], someImageView = nil; 

    [super dealloc]; 
} 

plutôt que

-(void)dealloc { 
    [anView release]; 
    [someImageView release]; 

    [super dealloc]; 
} 

Quelle est la raison de la mise à la terre de ces pointeurs sur nil (= "aucun objet"), après avoir appelé la libération? Laissez-moi deviner: Une autre méthode aurait pu «conserver» la vue pour une raison quelconque (n'importe quel exemple pour quand cela pourrait arriver?), Alors la chose didReceiveMemoryWarning arrive, et vous libérez une vue nib + entière qui n'est pas visible (ie dans une application multiview). Dès que l'utilisateur veut à nouveau voir cette vue, vous chargez rapidement la plume et ensuite: Il charge toutes les vues, connecte les prises, et BANG! Vos autres vues conservées sont suspendues maintenant sans aucun pointeur quelque part dans la brique de la mémoire, causant une fuite de mémoire importante et profonde jusqu'à ce que votre application tombe en panne.

Droit/Incorrect?

Répondre

1

plutôt que de faire de la libération de expicit et mis à zéro, si vos accesseurs ont des propriétés qui leur sont associées yoc et procédez comme suit comme une méthode plus concise:

- (void) dealloc 
{ 
    self.retainedProperty1 = nil; 
    self.retainedProperty2 = nil; 
    self.copiedProperty = nil; 
    self.assignedProperty = nil; 
} 

cette façon, vous pouvez avoir du code qui a moins répétition puisque le code synthétisé prendra soin de vos sorties pour vous. Editer: Je dois préciser que vos propriétés ne peuvent pas être en lecture seule ou bien que vous obtenez des erreurs de compilation pour des raisons évidentes.

+5

Non. Ceci est * explicitement * interdit par Apple, et un bon moyen de provoquer un crash dans certaines circonstances. Voir http://stackoverflow.com/questions/192721/why-shouldnt-i-use-obective-c-2-0-accessors-in-init-dealloc –

+0

Ce lien soulève un bon point, mais est-ce encore un mauvaise idée si vous ne l'utilisez que pour les propriétés readwrite entièrement synthétisées? (ce qui signifie que vous ne déclarez pas synthétiser pour une propriété et que vous écrasez toujours le getter ou le setter) – Kevlar

+0

C'est probablement très bien, pour l'instant, avec des propriétés entièrement synthétisées. Mais Apple ne garantit pas qu'il est autorisé et recommande contre cela, de sorte que cela pourrait casser dans tout futur SDK. –

14

Le principe est plus général que UIView. en effet, il est plus général que la méthode Objective-C/Cocoa -release. Il est également valable avec les fonctions de mémoire C malloc()/free().

Lorsque vous n'avez plus besoin d'objet ou de zone mémoire, vous devez d'abord le libérer/le libérer. Ensuite, pour vous assurer que vous ne l'utiliserez plus, effacez les moyens d'accéder à cet objet ou à cette zone en attribuant un nil à un objet ou un NULL à un pointeur de mémoire.

+4

+1. Le point principal est que le déréférencement d'un pointeur nul annule immédiatement l'exécution, tandis que le report d'un pointeur vers une mémoire déjà libérée peut "fonctionner" pendant un certain temps et entraîner des bogues désagréables. – zoul

+0

Merci. Je me demande pourquoi nous voyons si rarement ce modèle dans les exemples de code. Je ne l'ai jamais vu dans le code d'Apple. Mais ça me semble raisonnable de le faire, et je suppose que ça ne fera pas de mal de toute façon. – Thanks

+0

Exemple de code suit rarement les meilleures pratiques. le but de la plupart des exemples de code est de démontrer un principe, une API ou une méthode aussi concise que possible. – m4rkk

11

Some other method could have -retain'ed the view for some reason

À moins que vous invoquer dealloc vous, ce n'est appelé lorsque le nombre de conserver devient nul. Notez qu'en Objective-C envoyer un message à un "objet" nil est (souvent) parfaitement correct. Cela fera et non arrêter votre programme, mais le message est simplement ignoré. Cependant, vous ne pouvez pas envoyer un message à un objet libéré, ce qui provoquerait un plantage.

Donc, ce qui suit vous donnerait une erreur:

[anView release]; 
[anView doSomething]; 

Mais, cela est en fait ok:

[anView release]; 
anView = nil; 
[anView doSomething]; 

Il est une question de goût, mais pour ce qui précède, vous pourriez en fait préférer planter votre programme, plutôt que de se demander pourquoi faireQuelquechose n'est pas exécuté ...

Voir aussi Sending Messages to nil de Introduction to The Objective-C 2.0 Programming Language d'Apple.

2

J'utilise ce modèle beaucoup:

- (void) showHelp: (id) sender 
{ 
    if (helpController == nil) 
    { 
     helpController = [[HelpController alloc] initWithNibName: @"Help" bundle: [NSBundle mainBundle]]; 
    } 
    [self presentModalViewController: helpController animated: YES];  
} 
- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview 
    // Release anything that's not essential, such as cached data 
    [helpController release]; 
    helpController = nil; 
} 

Un peu partout que j'Allouer un viewcontroller qui est modal, ou autrement « temporaire ». De cette façon, il traîne si j'en ai besoin à nouveau, mais s'en va si la mémoire devient faible.

4

La méthode -dealloc est appelée lorsque l'objet est libéré et qu'aucune autre méthode sur l'objet ne sera exécutée après. Par conséquent, définir une variable d'instance sur zéro n'a aucun effet en dehors de cet objet.Si vous libérez un objet (sans utiliser de setter) ailleurs dans la classe, il est important de définir la variable d'instance sur nil pour empêcher le code d'envoyer un message à cette adresse.

+1

"aucune autre méthode sur l'objet ne sera exécutée après" - +1 pour cette explication claire de l'évidence. Merci! (Comme "important de mettre la variable d'instance à zéro pour empêcher le code ailleurs d'envoyer un message à cette adresse", je me demande pourquoi ignorer un message involontaire est préférable à l'obtention d'un message d'erreur ...) – Arjan

+3

bugs - même ceux bien testés libérés au client. Les types d'erreurs générées par l'envoi de messages à zéro (essentiellement un non-op) sont généralement moins graves que les erreurs générées par l'envoi d'un message à un objet libéré. Les premiers entraînent généralement des erreurs de logique lorsque le programme ne fonctionne pas exactement comme prévu, le second entraîne un crash. Au cours du développement, les plantages sont les bienvenus car ils permettent de trouver le bug - ce n'est pas le cas pour les produits publiés. – m4rkk