web-dev-qa-db-fra.com

faible ou fort pour IBOutlet et autres

J'ai basculé mon projet vers ARC et je ne comprends pas si je dois utiliser strong ou weak pour IBOutlets. Xcode fait ceci: dans le constructeur d'interface, si un créer un UILabel par exemple et que je le connecte avec l'éditeur assistant à mon ViewController, il crée ceci:

@property (nonatomic, strong) UILabel *aLabel;

Il utilise le strong, à la place j'ai lu un tutoriel sur le site Web de RayWenderlich qui dit ceci:

Mais pour ces deux propriétés particulières, j'ai d'autres plans. Au lieu de strong, nous les déclarerons comme weak.

@property (nonatomic, weak) IBOutlet UITableView *tableView;
@property (nonatomic, weak) IBOutlet UISearchBar *searchBar;

Weak est la relation recommandée pour toutes les propriétés outlet. Ces objets de vue font déjà partie de la hiérarchie de vues du contrôleur de vue et n'ont pas besoin d'être conservés ailleurs. Le gros avantage de déclarer vos points de vente weak est que cela vous fait gagner du temps lors de l'écriture de la méthode viewDidUnload.

Actuellement, notre viewDidUnload ressemble à ceci:

- (void)viewDidUnload
{
    [super viewDidUnload];
    self.tableView = nil;
    self.searchBar = nil;
    soundEffect = nil;
}

Vous pouvez maintenant le simplifier comme suit:

- (void)viewDidUnload
{
    [super viewDidUnload];
    soundEffect = nil;
}

Utilisez donc weak, au lieu de strong, et supprimez le jeu à nil dans le videDidUnload, à la place Xcode utilisez le strong, et utilisez le self... = nil dans le viewDidUnload.

Ma question est: quand dois-je utiliser strong, et quand weak? Je souhaite également utiliser pour la cible de déploiement iOS 4, alors quand dois-je utiliser le unsafe_unretain? Tout le monde peut m'aider à bien m'expliquer avec un petit tutoriel, lors de l'utilisation de strong, weak et unsafe_unretain avec ARC?

32
Piero

Une règle de base

Lorsqu'un parent a une référence à un objet enfant, vous devez utiliser une référence strong. Lorsqu'un enfant a une référence à son objet parent, vous devez utiliser une référence weak ou unsafe_unretained un (si le premier n'est pas disponible). Un scénario typique est lorsque vous traitez avec des délégués. Par exemple, un UITableViewDelegate ne conserve pas de classe de contrôleur qui contient une vue de table.

enter image description here

Voici un schéma simple pour présenter les principaux concepts.

Supposons que les premières A, B et C soient des références strong. En particulier, C a une référence strong à son parent. Lorsque obj1 est publié (quelque part), la référence A n'existe plus mais vous avez une fuite car il y a un cycle entre obj1 et obj2. S'exprimant en termes de nombre de retenues ( uniquement à des fins d'explication ), obj1 a un nombre de retenues de 2 (obj2 a une référence strong à it), alors que obj2 a un nombre de retenues de 1. Si obj1 est libéré, son nombre de retenues est maintenant de 1 et sa méthode dealloc n'est pas appelée. obj1 et obj2 restent toujours en mémoire mais personne n'y fait référence: Fuite .

Au contraire, si seuls A et B sont des références strong et C est qualifié de weak tout va bien. Vous n'avez aucune fuite. En fait, lorsque obj1 est publié, il libère également obj2. En termes de nombre de retenues, obj1 a un nombre de retenues de 1, obj2 a un nombre de retenues de 1. Si obj1 est libéré, son nombre de retenues est maintenant de 0 et sa méthode dealloc est appelée. obj1 et obj2 sont supprimés de la mémoire.

Une suggestion simple: commencez à penser en termes de graphique d'objet lorsque vous traitez avec ARC.

Concernant votre première question, les deux solutions sont valables lorsque vous traitez avec des XIB. En général, les références weak sont utilisées lorsque vous traitez avec des cycles de mémoire. En ce qui concerne les fichiers XIB, si vous utilisez strong, vous devez définir nil dans viewDidUnload car si vous ne le faites pas, dans des conditions de mémoire faible, vous pourriez provoquer des fuites inattendues. Vous ne les libérez pas dans dealloc car ARC le fera pour vous. weak n'a pas besoin de ce traitement car, lorsque l'objet cible est détruit, ces valeurs sont définies automatiquement comme nil. Plus de pointeurs pendants.

Si vous êtes intéressé, je vous suggère vraiment de lire friday-qa-2012-04-13-nib-memory-management by Mike Ash .

À propos de votre deuxième question, si vous devez prendre en charge iOS 4, au lieu de weak, vous devez utiliser unsafe_unretained.

Dans SO il y a beaucoup de questions/réponses. Voici les principales:

Comment remplacer les références faibles lorsque j'utilise ARC et que je cible iOS 4.0?

Quels types de fuites le comptage automatique des références dans Objective-C n'empêche-t-il pas ou ne minimise-t-il pas?

en utilisant ARC, assignation de qualificatif à vie et unsafe_unretained

fort/faible/conserver/unsafe_unretained/assigner

J'espère que cela pourra aider.

Mise à jour

Selon le commentaire de shaunlim, à partir d'iOS 6, la méthode viewDidUnload est déconseillée. Ici, je suggère vraiment de voir la réponse de Rob: iOS 6 - migrer viewDidUnload vers didReceiveMemoryWarning? .

69
Lorenzo B

Vous pouvez utiliser faible pour les objets qui sont connectés via IBOutlets aux objets dans IB parce que dans ce cas, les objets seront là aussi longtemps que la vue d'ensemble est là. En effet, la vue d'ensemble a un pointeur puissant vers ses sous-vues.

Si le pointeur que vous définissez est le seul pointeur vers un objet, vous devez le déclarer fort.

Si vous êtes un développeur enregistré, je vous recommande fortement de jeter un œil aux vidéos des WWDC11 et WWDC12. Une autre bonne ressource est le podcast de développement iOS de Stanford.

11
dasdom