Question

Dans la plupart des exemples, je vois la configuration suivante d'IBOutlets:



(Example A)

FooController.h:

@interface FooController : UIViewController {
    UILabel *fooLabel;
}

@property (nonatomic, retain) IBOutlet UILabel *fooLabel;

@end

FooController.m:

@implementation FooController

@synthesize fooLabel;

@end

Mais cela fonctionne aussi très bien (remarque: pas de propriété ni de synthèse):



(Example B)

FooController.h:

@interface FooController : UIViewController {
    IBOutlet UILabel *fooLabel;
}

@end

FooController.m:

@implementation FooController

@end

Existe-t-il des inconvénients à définir IBOutlets comme dans l'exemple B? Vous aimez les fuites de mémoire? Cela semble fonctionner correctement et je préfère ne pas exposer les IBOutlets en tant que propriétés publiques car ils ne sont pas utilisés tels quels, ils ne sont utilisés que dans l'implémentation du contrôleur. Le définir à trois endroits sans réel besoin ne me semble pas très sec (ne vous répétez pas).

Était-ce utile?

La solution

Sous Mac OS X, les IBOutlets sont connectés comme suit:

  1. Recherchez une méthode appelée set < OutletName >:. S'il existe, appelez-le.
  2. Si aucune méthode n'existe, recherchez une variable d'instance nommée < OutletName > ;, définissez-la sans conserver .

Sur l'iPhone OS, les IBOutlets sont connectés comme suit:

  1. appelez [objet setValue: outletValue forKey: @ "< OutletName >"]

Le comportement de la valeur définie pour la clé est de faire quelque chose comme ceci:

  1. Recherchez une méthode appelée set < OutletName >:. S'il existe, appelez-le.
  2. Si aucune méthode n'existe, recherchez une variable d'instance nommée < OutletName > ;, définissez-la et conservez-la .

Si vous utilisez une propriété, vous tomberez dans "& em; Rechercher une méthode appelée set < OutletName >: ... ". cas sur les deux plates-formes. Si vous utilisez uniquement une variable d'instance, vous aurez un comportement conservation / libération différent sur Mac OS X et iPhone OS. Il n'y a rien de mal à utiliser une variable d'instance, il vous suffit de gérer cette différence de comportement lorsque vous changez de plate-forme.

Voici un lien vers la documentation complète sur ce sujet uniquement. https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/CocoaNibs.html#//apple_ref/doc/uid/10000051i-CH4-SW6 . / p>

Autres conseils

Sous Mac OS X, les IBOutlets ne sont pas conservés par défaut. C'est le contraire du comportement sur iPhone OS: sur iPhone OS, si vous ne déclarez pas une propriété, celle-ci est conservée et vous devez la publier dans la méthode dealloc . En outre, le moteur d'exécution 64 bits peut synthétiser des variables d'instance à l'aide de déclarations de propriétés. Cela signifie qu'un jour, les variables d'instance (avec IBOutlet ) peuvent être omises.

Pour ces raisons, il est plus homogène et compatible de toujours créer une propriété et d’utiliser le IBOutlet uniquement dans la propriété. Malheureusement, c'est aussi plus verbeux.

Dans votre premier exemple, vous devez toujours libérer la sortie dans la méthode dealloc . Dans votre deuxième exemple, vous devez libérer la prise uniquement avec iPhone OS.

Le résultat final est exactement identique, mais vous devez garder à l’esprit quelques points:

  • Lorsque vous utilisez des champs d'instance comme points de vente, vous ne devez PAS les publier dans dealloc .

  • Lorsque vous utilisez des propriétés ayant l'attribut (keep), vous devez libérer la propriété dans dealloc (à l'aide de self.property = nil ou en libérant la variable de sauvegarde). Cela rend beaucoup plus transparent ce qui se passe.

En fait, tout se résume à la même vieille règle: " vous libérerez ce que vous allouez / conservez ". Donc, si vous utilisez un champ d'instance comme point de vente, vous ne l'avez ni alloué ni conservé, vous ne devriez donc pas le publier.

Il est possible que ces exemples utilisent la retenue, car l'exemple de code alloue et initialise par programme un UILabel, puis l'ajoute à UIView. C’est le cas de nombreux exemples, car apprendre à utiliser Interface Builder n’est souvent pas leur objectif.

Le deuxième exemple (aucune propriété et aucune synthèse) avec IBOutlet est utilisé lorsque le développeur "attribue" l'UILabel (Button, View, etc.) dans Interface Builder - en faisant glisser IBOulet vers l'étiquette ou un autre composant View. . À mon avis, l'action précédente de glisser-déposer (Libellé sur la vue) ajoute également la sous-vue, le libellé à une vue - et ainsi de suite. L'étiquette est conservée par une vue; une vue est conservée par fenêtre; La fenêtre est conservée par le propriétaire du fichier. Le propriétaire du fichier est généralement votre document qui est démarré en mode principal.

Vous remarquerez que lorsque vous parcourez votre programme (en ajoutant un awakeFromNib

- (void)awakeFromNib
{
    [fooLabel blahblah];
}

ce fooLabel a déjà une adresse mémoire.

C’est parce que l’étiquette a été initialisée à partir d’un groupe de fichiers (le fichier nib) en utilisant non init mais initWithCoder. Ce qui désérialise essentiellement le flux de fichiers en objet - puis définit la variable IBOutlet. (Nous parlons toujours de la méthode IBOutlet).

Notez également que la méthode iOS susmentionnée utilise la méthode Valeur de clé

  call [object setValue:outletValue forKey:@"<OutletName>"]

qui est le motif Observer / Observable. Ce modèle nécessite que l’objet Observable fasse référence à chaque observateur d’un ensemble / groupe. Un changement de valeur itérera le Set / Array et mettra également à jour tous les observateurs. Cet ensemble conservera déjà chaque observateur, d’où son absence dans iOS.

Ensuite, le reste n'est que spéculation.

Il semble que les cas où vous utilisez ensuite Interface Builder

 @property (nonatomic, retain) IBOutlet UILabel *fooLabel;

devrait éventuellement être remplacé par

@property (nonatomic, weak) IBOutlet UILabel *fooLabel;

ou     @property (nonatomic, assign) IBOutlet UILabel * fooLabel;

Ensuite, il n’est pas nécessaire de le publier dans une méthode dealloc. De plus, il répondra aux exigences OSX et iOS.

Cela est basé sur la logique et il se peut que certaines pièces me manquent.

Néanmoins, le point de vue peut persister peu importe la durée de votre programme. Alors qu’une étiquette dans une boîte de dialogue modale (ouvrir, fermer, ouvrir, fermer) peut en fait avoir été trop conservée et avoir des fuites par cycle. Et c’est parce que (de nouveau, la spéculation) chaque boîte de dialogue fermée est sérialisée dans un système de fichiers et conserve ainsi la position et la taille x, y, ainsi que ses sous-vues, etc. Et ensuite désérialisée ... à la prochaine session ouverte (Opposé pour dire minimiz ou caché.)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top