iOS – Quelle est la meilleure façon de gérer la memory pour IBOutlets?

J'ai passé en revue les docs d'Apple et l'exemple de code pour essayer de déterminer la meilleure manière de gérer la memory pour IBOutlets. Je suis un peu confus, c'est le less qu'on puisse dire.

L'exemple de code CurrentAddress déclare IBOutlets en tant que propriétés:

@interface MapViewController : UIViewController <MKMapViewDelegate, MKReverseGeocoderDelegate> { MKMapView *mapView; UIBarButtonItem *getAddressButton; } @property (nonatomic, retain) IBOutlet MKMapView *mapView; @property (nonatomic, retain) IBOutlet UIBarButtonItem *getAddressButton; 

Génial. Et ceux-ci sont publiés dans dealloc:

 - (void)dealloc { [mapView release]; [getAddressButton release]; [super dealloc]; } 

Ces propriétés ne doivent-elles pas être définies pour affecter? Parce que lorsqu'il est défini pour conserver, le nombre de retenue IBOutlet sera augmenté deux fois: une fois lorsque la pointe est chargée et une autre fois lorsque la propriété est définie? Et ne vaudrait-il pas mieux mettre ces propriétés à zéro au lieu de les libérer en dealloc?

Apple docs dit que nous devrions conserver les propriétés pour iOS.
Les sockets retenues doivent être libérées et viewDidUnload à la fois dans dealloc et viewDidUnload .

Sur Mac, chaque prise qui n'est pas conservée par une vue d'set est automatiquement conservée lors du chargement de la plume. Ce n'est pas le cas avec iOS. C'est pourquoi il est théoriquement valable de ne conserver que les points de vente autres que les vues dans la hiérarchie des vues.

Jeff LaMarche a publié un article très utile à ce sujet: Outlets, Cocoa vs Cocoa Touch .

Une fois que le chargeur de plume a fini de tout charger et de connecter tous les IBOutlets, il libère tous les objects qu'il a chargés. Si votre propriété IBOutlet a été déclarée en tant qu'affect, l'object vers lequel elle pointe sera supprimé la prochaine fois que le pool autorelease sera vidé.

Vous pouvez définir les propriétés à zéro dans dealloc au lieu de les libérer directement, le résultat est le même. La chose à surveiller est, si vous avez fourni votre propre implémentation du setter, vous devez garder à l'esprit que certains des autres membres de votre object ont déjà été libérés.

C'est différent pour MacOSX et iOS. Dans iOS, le nombre de réceptions sera de deux après le chargement de la vue et l'établissement des connections de pointe.

Chacun de ces éléments sera retenu une fois par la vue et une fois par votre controller. Les éléments supplémentaires dans la vue ne seront conservés que par la vue uniquement.

Lorsque votre controller relâche les deux éléments, leur nombre de retenues descend à un. Après cela, [super dealloc] est appelé. UIViewController a une version [view release] dans son dealloc, donc la vue est libérée (sauf si elle est conservée ailleurs, ou précédemment publiée). Lorsque la vue est désallouée, elle libère ses sous-vues, et les éléments sont finalement complètement libérés.

La raison pour laquelle [release d'object] est préférée dans dealloc, est que le encoding de valeur-key (ou votre propre code) peut entraîner l'exécution de code supplémentaire lorsque vous écrivez [self setObject: nil]. Cela peut potentiellement provoquer l'interaction d'autres objects avec votre controller lorsqu'il est en train de se désallouer lui-même. Les setters ne doivent pas être utilisés dans la méthode init pour la même raison.

Il y a une deuxième raison pour juste faire la libération. En laissant la valeur et en ne la définissant pas à zéro, nous remarquerons si le code accède par erreur à cette variable sur notre object plus tard pendant dealloc. Cela peut aider à attraper les bogues qui pourraient ne pas être faciles à repérer autrement.

Je suppose que vous @synthesize ces propriétés. Si vous ne l'avez pas fait, vous devrez vous libérer manuellement. Vous avez très raison de supposer que si vous continuiez à conserver quand une propriété est définie, vous fuiriez la memory.

Pensons … à quoi ressemblaient les propriétés avant d'avoir l' @synthesize fantaisie @synthesize ?

 id _propertyName; // the ivar - (id) propertyName { return _propertyName; } - (void) setPropertyName:(id)v { if (_propertyName) { [_propertyName release]; // release the previously retained property } _propertyName = [v retain]; // retain this one so it doesn't fly away on us } 

Maintenant, vous n'avez pas besoin de taper ce truc, parce que @synthesize est cool et génère ça pour vous, il va aussi générer des blocs @synchronized si vous ne spécifiez pas quelque chose comme étant nonatomic , ce qui est aussi joli.

Si vous spécifiez assign au lieu de retain , vous obtiendrez quelque chose comme ça

 id _propertyName; // the ivar - (id) propertyName { return _propertyName; } - (void) setPropertyName:(id)v { _propertyName = v; } 

C'est à peu près la seule chose que vous pouvez faire quand les choses ne sont pas des objects, car ce ne sont que des valeurs (aussi parfois appelées types de valeur, les objects sont des types de reference). Puisque les types de valeur ne peuvent pas être conservés, l'autre type de bloc n'aurait aucun sens. Allez-y et essayez de créer une propriété de retenue avec BOOL et regardez ce que LLVM ou GCC vous disent d'aller faire avec quoi;)

ces propriétés ne doivent-elles pas être définies pour affecter? Parce que lorsqu'il est défini pour conserver, le nombre de retenue IBOutlet sera augmenté deux fois: une fois lorsque la pointe est chargée et une autre fois lorsque la propriété est définie

Eh bien, le code que vous avez posté est juste comme il est.

lorsque vous utilisez:

 @property (nonatomic, retain) IBOutlet MKMapView *mapView; 

vous venez de dire à xCode de créer une méthode setter qui créera votre object MKMapView et le conservera à chaque appel

 yourMapViewController.mapView = someMapView; // from out // or self.mapView = someMapView; // from in 

après que mapView conserve l'augmentation du nombre +1 et que votre code MapViewController ait besoin de 'couse maintenant, vous pouvez pointer vers mapView et le gérer …

ne vous inquiétez pas pour le file IB nib …

Lorsque vous chargez un UIViewController avec une plume, dans votre cas, la class MapViewController: UIViewController, les objects de plume IB seront libérés lorsque vous relâcherez votre MapViewController … attention à l'object que vous retenez …