560 votes

Les IBOutlets doivent-ils être forts ou faibles sous l'ARC ?

Je développe exclusivement pour iOS 5 en utilisant ARC. Est-ce que IBOutlet s à UIView (et les sous-classes) soient strong o weak ?

Les suivantes :

@property (nonatomic, weak) IBOutlet UIButton *button;

Je me débarrasserais de tout ça :

- (void)viewDidUnload
{
    // ...
    self.button = nil;
    // ...
}

Cela pose-t-il des problèmes ? Les modèles utilisent strong tout comme les propriétés générées automatiquement lorsqu'on se connecte directement à l'en-tête à partir de l'éditeur "Interface Builder", mais pourquoi ? Le site UIViewController a déjà un strong référence à son view qui conserve ses sous-vues.

11 votes

A titre d'information, IBOutletCollection() ne doit pas être weak sinon, il retourne comme nil .

0 votes

Xcode 8.2.1 utilise des faiblesses lors de la création de IBOutlets via le constructeur d'interface. Cependant, de nombreuses réponses ici sur SO conseillent d'utiliser strong.

1 votes

@neoneye Je viens d'essayer avec xcode 8.3.2 de glisser du storyboard vers le fichier swift et il s'agit par défaut de strong

453voto

Alexsander Akers Points 9635

AVERTISSEMENT, RÉPONSE PÉRIMÉE Cette réponse n'est pas à jour par rapport à la WWDC 2015, pour la réponse correcte, veuillez vous référer à la page de la WWDC 2015. réponse acceptée (Daniel Hall) ci-dessus. Cette réponse restera dans les archives.


Résumé de l'étude bibliothèque de développeurs :

D'un point de vue pratique, dans iOS et OS X, les points de vente doivent être définis comme des propriétés déclarées. Les sorties doivent généralement être faibles, à l'exception de celles du propriétaire du fichier vers les objets de niveau supérieur d'un fichier nib (ou, dans iOS, d'une scène de storyboard) qui doivent être fortes. Les outlets que vous créez seront donc généralement faibles par défaut, car :

  • Les sorties que vous créez vers, par exemple, des sous-vues de la vue d'un contrôleur de vue ou de la fenêtre d'un contrôleur de fenêtre, sont des références arbitraires entre objets qui n'impliquent pas de propriété.

  • Les points de sortie forts sont souvent spécifiés par des classes de cadre (par exemple, le point de sortie de la vue de UIViewController, ou le point de sortie de la fenêtre de NSWindowController).

    @property (weak) IBOutlet MyView *viewContainerSubview;
    @property (strong) IBOutlet MyOtherClass *topLevelObject;

10 votes

Comment avez-vous réussi à faire en sorte que le lien "developer library" renvoie à la partie spécifique de la page de la documentation Apple ? Chaque fois que je crée un lien vers la documentation sur la pomme, il renvoie toujours vers le haut de la page (même si le contenu qui nous intéresse se trouve au milieu de la page). Merci.

69 votes

J'ai copié le lien depuis le volet de navigation de gauche. :D

28 votes

Que signifie "à l'exception de ceux qui vont du propriétaire du fichier aux objets de niveau supérieur dans un fichier nib (ou, dans iOS, une scène de storyboard)" ?

51voto

Tammo Freese Points 5648

Bien que la documentation recommande d'utiliser weak sur les propriétés pour les sous-vues, depuis iOS 6, il semble être possible d'utiliser strong (le qualificatif de propriété par défaut) à la place. C'est dû au changement dans UIViewController que les vues ne sont plus déchargées.

  • Avant iOS 6, si vous conserviez des liens forts vers des sous-vues de la vue du contrôleur, si la vue principale du contrôleur était déchargée, ces liens s'accrochaient aux sous-vues tant que le contrôleur était présent.
  • Depuis iOS 6, les vues ne sont plus déchargées, mais chargées une fois et restent en place tant que leur contrôleur est présent. Les propriétés fortes n'ont donc plus d'importance. Elles ne créeront pas non plus de cycles de référence forte, puisqu'elles pointent vers le bas du graphe de référence forte.

Cela dit, je suis partagé entre l'utilisation

@property (nonatomic, weak) IBOutlet UIButton *button;

y

@property (nonatomic) IBOutlet UIButton *button;

dans iOS 6 et suivants :

  • Utilisation de weak indique clairement que le contrôleur ne veut pas la propriété du bouton.

  • Mais en omettant weak ne fait pas de mal dans iOS 6 sans déchargement de la vue, et est plus courte. Certains pourraient faire remarquer que c'est aussi plus rapide, mais je n'ai encore jamais rencontré une application qui soit trop lente à cause de weak IBOutlet s.

  • Ne pas utiliser weak peut être perçue comme une erreur.

En résumé : Depuis iOS 6, nous ne pouvons plus nous tromper tant que nous n'utilisons pas le déchargement des vues. Il est temps de faire la fête ;)

0 votes

C'est vrai, mais vous pouvez toujours vouloir décharger la vue vous-même. Dans ce cas, vous devrez définir toutes vos sorties sur nil manuellement.

0 votes

PS : weak est un peu moins cher en ARM64 :D

0 votes

C'est vrai, si vous implémentez le déchargement des vues, weak propriétés ou __weak Les variables d'instance sont la solution. Je voulais juste souligner qu'il y a moins de risques d'erreur ici. Comme pour weak étant moins cher sur arm64, je n'ai même pas vu un problème de performance dans la vie réelle avec weak IBOutlet s sur armv7. :)

34voto

Je ne vois pas de problème à cela. Avant l'ARC, j'ai toujours fait en sorte que mes IBOutlets assign car ils sont déjà retenus par leurs supervisions. Si vous les faites weak vous ne devriez pas avoir à les réduire à néant dans viewDidUnload, comme vous le faites remarquer.

Un bémol : vous pouvez prendre en charge iOS 4.x dans un projet ARC, mais si vous le faites, vous ne pouvez pas utiliser weak donc tu dois les faire assign dans ce cas, vous voudrez toujours rendre nulle la référence dans viewDidUnload pour éviter un pointeur qui pendouille. Voici un exemple d'un bug de type "dangling pointer" que j'ai rencontré :

Un UIViewController possède un UITextField pour le code postal. Il utilise CLLocationManager pour inverser le géocodage de l'emplacement de l'utilisateur et définir le code postal. Voici le callback du délégué :

-(void)locationManager:(CLLocationManager *)manager
   didUpdateToLocation:(CLLocation *)newLocation
          fromLocation:(CLLocation *)oldLocation {
    Class geocoderClass = NSClassFromString(@"CLGeocoder");
    if (geocoderClass && IsEmpty(self.zip.text)) {
        id geocoder = [[geocoderClass alloc] init];
        [geocoder reverseGeocodeLocation:newLocation completionHandler:^(NSArray *placemarks, NSError *error) {
            if (self.zip && IsEmpty(self.zip.text)) {
                self.zip.text = [[placemarks objectAtIndex:0] postalCode];
            }
        }];    
    }
    [self.locationManager stopUpdatingLocation];
}

J'ai découvert que si je rejetais cette vue au bon moment et que je ne mettais pas à zéro self.zip dans le fichier viewDidUnload le callback du délégué pourrait lancer une exception de mauvais accès sur self.zip.text.

4 votes

Je crois également savoir que weak les propriétés ne doivent pas être remplies viewDidUnload . Mais pourquoi le modèle d'Apple pour la création de points de vente inclut-il un [self setMySubview:nil] ?

3 votes

Existe-t-il des cas réels où l'utilisation de strong/retained pour votre IBOutlet pourrait poser problème ? Ou s'agit-il simplement d'un retain redondant, ce qui signifie un mauvais style de codage mais n'affecterait pas votre code ?

1 votes

Existe-t-il une chose telle qu'une retenue redondante ? S'il y a un retain supplémentaire, il ne sera pas compté correctement et ne sera donc pas libéré aussi vite qu'il le pourrait puisqu'il y a un retain supplémentaire dans son compte de retain.

20voto

Giuseppe Points 3562

Dans le développement iOS, le chargement des NIB est un peu différent du développement Mac.

Dans le développement Mac, une IBOutlet est généralement une référence faible : si vous avez une sous-classe de NSViewController, seule la vue de premier niveau sera conservée et lorsque vous désallouez le contrôleur, toutes ses sous-vues et sorties sont libérées automatiquement.

UiViewController utilise le Key Value Coding pour définir les points de vente en utilisant des références fortes. Ainsi, lorsque vous désallouez votre UIViewController, la vue supérieure est automatiquement désallouée, mais vous devez également désallouer toutes ses sorties dans la méthode dealloc.

Dans ce billet du Big Nerd Ranch Les auteurs traitent de ce sujet et expliquent également pourquoi l'utilisation d'une référence forte dans IBOutlet n'est pas un bon choix (même si elle est recommandée par Apple dans ce cas).

16 votes

Elle l'explique comme en 2009. Avec l'ARC, cela a considérablement changé.

1 votes

Le lien du Big Nerd Ranch est mort pourtant j'ai vraiment besoin de le lire. Quelqu'un connaît-il plus de détails sur ce post, pour que je puisse le retrouver ?

0 votes

@MottiShneor ne vous inquiétez pas, ce n'est pas grave puisque le lien concernait des périodes antérieures à l'ARC et n'est plus pertinent.

6voto

landonandrey Points 64

Faites attention, IBOutletCollection devrait être @property (strong, nonatomic) .

3 votes

Pourquoi pas ? copy car il s'agit d'un NSArray ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X