Question IBOutlets doit-il être fort ou faible sous ARC?


Je développe exclusivement pour iOS 5 en utilisant ARC. Devrait IBOutlets à UIViews (et sous-classes) être strong ou weak?

Le suivant:

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

Se débarrasser de tout cela:

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

Y a-t-il des problèmes à faire cela? Les modèles utilisent strong comme le sont les propriétés générées automatiquement lors de la connexion directe à l'en-tête à partir de l'éditeur 'Interface Builder', mais pourquoi? le UIViewController a déjà un strong référence à son view qui conserve ses sous-vues.


514
2017-10-06 17:56


origine


Réponses:


La meilleure pratique actuellement recommandée par Apple est que les IBOutlets soient fort sauf si faible est spécifiquement nécessaire pour éviter un cycle de conservation. Comme Johannes l'a mentionné ci-dessus, ceci a été commenté dans la session "Implémenter les Designs de l'interface utilisateur dans Interface Builder" de la WWDC 2015 où un Ingénieur Apple a déclaré:

Et la dernière option que je veux souligner est le type de stockage, qui peut   soit être fort ou faible. En général, vous devriez faire votre sortie   fort, surtout si vous connectez une prise à une sous-vue ou à   une contrainte qui ne sera pas toujours conservée par la vue   hiérarchie. La seule fois où vous avez vraiment besoin de faire un débouché faible, c'est si   vous avez une vue personnalisée qui référence quelque chose sauvegardant la vue   hiérarchie et en général ce n'est pas recommandé.

J'ai demandé à ce sujet sur Twitter à un ingénieur de l'équipe de l'IB et il a confirmé que fort devrait être la valeur par défaut et que les documents du développeur sont mis à jour.

https://twitter.com/_danielhall/status/620716996326350848 https://twitter.com/_danielhall/status/620717252216623104


185
2017-07-14 00:59



AVERTISSEMENT, RÉPONSE RÉDUITE: cette réponse n'est pas à jour selon WWDC 2015, pour la bonne réponse se référer à la réponse acceptée (Daniel Hall) ci-dessus. Cette réponse restera pour enregistrement.


Résumée de la bibliothèque de développeur:

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

  • Les points de vente que vous créez, 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 des objets qui n'impliquent pas la propriété.

  • Les sorties puissantes sont fréquemment spécifiées par les classes de structure (par exemple, le point de vue de UIViewController ou la sortie de fenêtre de NSWindowController).

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

444
2017-10-11 16:10



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

  • Avant iOS 6, si vous conserviez des liens forts vers les sous-vues de la vue du contrôleur, si la vue principale du contrôleur de vue était déchargée, celles-ci retiendraient les sous-vues tant que le contrôleur de vue serait présent.
  • Depuis iOS 6, les vues ne sont plus déchargées, mais chargées une fois, puis restent là aussi longtemps que leur contrôleur est là. Les propriétés si fortes ne comptent pas. Ils ne créeront pas non plus de cycles de référence forts, puisqu'ils pointent vers le bas le graphique de référence fort.

Cela dit, je suis déchiré entre l'utilisation

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

et

@property (nonatomic) IBOutlet UIButton *button;

dans iOS 6 et après:

  • En utilisant weak indique clairement que le contrôleur ne veut pas posséder le bouton.

  • Mais en omettant weak ne fait pas mal dans iOS 6 sans déchargement de vue, et est plus courte. Certains peuvent souligner que c'est aussi plus rapide, mais je n'ai pas encore rencontré une application qui est trop lente à cause de weak  IBOutlets.

  • N'utilise pas weak peut être perçu comme une erreur.

Bottom line: 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. ;)


46
2017-12-10 21:54



Je ne vois aucun problème avec ça. Avant ARC, j'ai toujours fait mes IBOutlets assign, comme ils sont déjà retenus par leurs superviews. Si vous les faites weak, vous ne devriez pas avoir à les exclure dans viewDidUnload, comme vous le signalez.

Une mise en garde: vous pouvez soutenir iOS 4.x dans un projet ARC, mais si vous le faites, vous ne pouvez pas utiliser weak, donc tu devrais les faire assign, auquel cas vous voudriez toujours nil la référence dans viewDidUnload pour éviter un pointeur qui pend. Voici un exemple de bug pointeur que j'ai rencontré:

Un UIViewController a 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 rappel 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 trouvé que si je rejetais ce point de vue au bon moment et n'a pas nil auto.zip dans viewDidUnload, le rappel de délégué pourrait jeter une mauvaise exception d'accès sur self.zip.text.


34
2017-10-07 22:34



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

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

UiViewController utilise Key Value Coding pour définir les sorties en utilisant des références fortes. Ainsi, lorsque vous libérez votre UIViewController, la vue de dessus est automatiquement désaffectée, mais vous devez également libérer tous ses points de vente dans la méthode dealloc.

Dans ce post du Big Nerd Ranch, ils couvrent ce sujet et expliquent aussi pourquoi l'utilisation d'une référence forte dans IBOutlet n'est pas un bon choix (même si c'est recommandé par Apple dans ce cas).


20
2017-10-10 16:02



IBOutlet devrait être forte, pour des raisons de performance. Voir Référence Storyboard, IBOutlet fort, Scene Dock dans iOS 9

Comme expliqué dans ce paragraphe, les points de vue des sous-vues de la vue   la vue du contrôleur peut être faible, car ces sous-vues sont déjà   appartenant à l'objet de niveau supérieur du fichier nib. Cependant, quand une sortie   est défini comme un pointeur faible et le pointeur est défini, ARC appelle le   fonction d'exécution:

id objc_storeWeak(id *object, id value); 

Cela ajoute le pointeur   (objet) à une table en utilisant la valeur de l'objet en tant que clé. Cette table est   dénommé la table faible. ARC utilise cette table pour stocker tous les   points faibles de votre application. Maintenant, lorsque la valeur de l'objet est   désaffecté, ARC va itérer sur la table faible et mettre le faible   référence à zéro. Alternativement, l'ARC peut appeler:

void objc_destroyWeak(id * object)

Ensuite, l'objet est   appels non enregistrés et objc_destroyWeak à nouveau:

objc_storeWeak(id *object, nil)

Cette comptabilité associée   avec une référence faible peut prendre 2-3 fois plus longtemps au cours de la libération d'un   référence forte. Ainsi, une référence faible introduit un surcoût pour   durée d'exécution que vous pouvez éviter en définissant simplement les points de vente comme forts.

À partir de Xcode 7, il suggère strong

Si vous regardez la session de WWDC 2015 407 Implémentation de conceptions d'interface utilisateur dans Interface Builder, il suggère (transcription de http://asciiwwdc.com/2015/sessions/407)

Et la dernière option que je veux signaler est le type de stockage, qui peut être fort ou faible.

En général, vous devez renforcer votre point de vente, en particulier si vous connectez un point de vente à une sous-vue ou à une contrainte qui ne sera pas toujours conservée par la hiérarchie de vues.

La seule fois où vous avez vraiment besoin de rendre un débouché faible est si vous avez une vue personnalisée qui fait référence à quelque chose sauvegarder la hiérarchie de la vue et en général ce n'est pas recommandé.

Donc je vais choisir fort et je clique sur connect qui va générer mon outlet.


14
2017-11-04 04:27



Une chose que je tiens à souligner ici, et ce, malgré ce que les ingénieurs d'Apple ont déclaré dans leur propre vidéo WWDC 2015 ici:

https://developer.apple.com/videos/play/wwdc2015/407/

Apple ne cesse de changer d'avis sur le sujet, ce qui nous indique qu'il n'y a pas de réponse unique à cette question. Pour montrer que même les ingénieurs d’Apple sont divisés sur ce sujet, jetez un coup d’œil au plus récent exemple de code, et vous verrez que certaines personnes utilisent faible, et d'autres pas.

Cet exemple Apple Pay utilise faible: https://developer.apple.com/library/ios/samplecode/Emporium/Listings/Emporium_ProductTableViewController_swift.html#//apple_ref/doc/uid/TP40016175-Emporium_ProductTableViewController_swift-DontLinkElementID_8

Comme le fait cet exemple d'image dans l'image: https://developer.apple.com/library/ios/samplecode/AVFoundationPiPPlayer/Listings/AVFoundationPiPPlayer_PlayerViewController_swift.html#//apple_ref/doc/uid/TP40016166-AVFoundationPiPPlayerViewerController_swift-DontLinkElementID_4

Comme le fait l'exemple de Lister: https://developer.apple.com/library/ios/samplecode/Lister/Listings/Lister_ListCell_swift.html#//apple_ref/doc/uid/TP40014701-Lister_ListCell_swift-DontLinkElementID_57

Comme le fait l'exemple du Core Location: https://developer.apple.com/library/ios/samplecode/PotLoc/Listings/Potloc_PotlocViewController_swift.html#//apple_ref/doc/uid/TP40016176-Potloc_PotlocViewController_swift-DontLinkElementID_6

Tout comme l'exemple de prévisualisation du contrôleur de vue: https://developer.apple.com/library/ios/samplecode/ViewControllerPreviews/Listings/Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift.html#//apple_ref/doc/uid/TP40016546-Projects_PreviewUsingDelegate_PreviewUsingDelegate_DetailViewController_swift-DontLinkElementID_5

Comme l'exemple HomeKit: https://developer.apple.com/library/ios/samplecode/HomeKitCatalog/Listings/HMCatalog_Homes_Action_Sets_ActionSetViewController_swift.html#//apple_ref/doc/uid/TP40015048-HMCatalog_Homes_Action_Sets_ActionSetViewController_swift-DontLinkElementID_23

Tous ceux-ci sont entièrement mis à jour pour iOS 9, et tous utilisent des points faibles. De cela, nous apprenons que A. Le problème n'est pas aussi simple que certains le prétendent. B. Apple a changé d'avis à plusieurs reprises, et C. Vous pouvez utiliser tout ce qui vous rend heureux :)

Un merci spécial à Paul Hudson (auteur de www.hackingwithsift.com) qui m'a donné la clarification, et les références pour cette réponse.

J'espère que cela clarifie un peu mieux le sujet!

Prends soin.


11
2018-05-05 21:25



De WWDC 2015 il y a une session sur Implémentation de conceptions d'interface utilisateur dans Interface Builder. Autour de la marque de 32min il dit que vous voulez toujours faire votre @IBOutlet  fort.


8
2017-07-09 13:11