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 commeweak
.
@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 venteweak
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?
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.
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?
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? .
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.