56 votes

Doit chaque ivar être une propriété?

Je vois recommandé partout lorsque l'on code pour iOS que les propriétés devraient être utilisées pour accéder aux variables d'instance en raison des avantages que cela apporte à la gestion de la mémoire, entre autres choses.

Cet avis ne me convainc pas vraiment. Je trouve que l'utilisation de propriétés au lieu de simples ivars nécessite trop de code et je ne vois pas vraiment les avantages si vous êtes à l'aise avec la gestion de la mémoire. Est-ce vraiment si important? Quelle est votre approche pour gérer les variables d'instance?

78voto

Daniel Dickison Points 15182

Il n'est pas vraiment nécessaire de déclarer des propriétés pour toutes les ivars. Quelques points viennent à l'esprit :

  • Si une ivar n'est assignée qu'une fois pendant la durée de vie de l'objet, vous ne gagnez rien en déclarant une propriété. Il suffit de retenir/copier/assigner lors de l'init puis de libérer selon les besoins lors du dealloc.
  • Si une ivar va être fréquemment modifiée, déclarer une propriété et utiliser toujours les accesseurs rendra plus facile d'éviter les erreurs de gestion de mémoire.
  • Vous pouvez déclarer des propriétés dans une extension de classe dans le fichier .m plutôt que dans le fichier .h si les propriétés et les ivars sont censés être privés.
  • Lors du ciblage d'iOS 4.0+, vous n'avez pas besoin de déclarer les ivars du tout dans votre en-tête si vous définissez une propriété et synthétisez les accesseurs.

Donc, j'utilise généralement des propriétés, mais pour des choses comme un NSMutableArray qu'un objet alloue pendant l'init et utilise pour contenir un tas de choses, j'utiliserai simplement une vieille ivar car je ne réassignerai jamais l'ivar.

51voto

bbum Points 124887

Alors que la réponse de Daniel est correcte, je pense qu'elle laisse de côté un point important. Notamment:

Je trouve que l'utilisation de propriétés au lieu de simples ivars prend juste trop de code et je ne vois pas vraiment les avantages si vous êtes à l'aise avec la gestion de la mémoire.

Les avantages sont la cohérence; une gestion mémoire cohérente et un comportement cohérent.

À noter que ces deux lignes de code peuvent en fait avoir un comportement extrêmement différent à l'exécution:

iVar = [foo retain];
self.iVar = foo;

Le premier est un réglage direct de la variable d'instance et il n'y aura pas de notifications de changement. Le second passe par le setter et, donc, préserve toutes les personnalisations de sous-classes lors de la définition et assure que tout observateur de la propriété est notifié du changement.

Si vous utilisez des ivars directement dans votre code (à l'intérieur de la classe - si vous utilisez des ivars d'une instance directement de l'extérieur de cette instance, eh bien... tout sous-traitant travaillant sur votre base de code devrait doubler ses tarifs ;), alors vous devez également gérer manuellement la propagation de la notification de changement (typiquement en appelant willChangeValueForKey:/didChangeValueForKey) ou bien ingénierie explicitement votre application pour éviter l'utilisation de mécanismes qui reposent sur l'observation Key-Value.

Vous dites "prend trop de code". Je ne vois pas ça; dans les deux lignes de code ci-dessus, la syntaxe du point est moins de caractères. Même appeler la méthode setter en utilisant la syntaxe traditionnelle serait moins de code.

Et ne sous-estimez pas la valeur de la centralisation de la gestion mémoire; une omission accidentelle dans une myriade de sites d'appel et c'est la ville du crash.

3voto

Simone D'Amico Points 848

Les propriétés ne sont que du sucre syntaxique qui vous évite d'écrire les mêmes méthodes encore et encore. Avec une propriété, vous avez un setter qui libère l'ancien objet et conserve le nouveau gratuitement.

1voto

Max O Points 473

Pour les champs privés - je suggère qu'il est prudent d'utiliser uniquement des ivars directs pour les types primitifs (BOOL/int/float etc). Je trouve qu'une bonne pratique est d'encapsuler tout ce qui concerne la gestion de la mémoire dans les propriétés - même pour les champs rarement utilisés. Un avantage supplémentaire de cette approche est que l'IDE met généralement en surbrillance l'accès aux ivars directement, ce qui permet d'avoir une belle séparation entre les champs scalaires simples et les champs de type objet.

Contrairement à cela, je déconseillerais fortement tout ivars direct dans l'interface publique de la classe. En raison de la nature dynamique du langage, cela peut entraîner des erreurs d'exécution extrêmement difficiles à trouver, localiser et corriger. Considérez la hiérarchie suivante

@interface BaseControl
...
@end

@interface Label : BaseControl
...
@end

@interface Button : BaseControl {
  @public
    BOOL enabled;
}
@end

et un extrait de code

- (void)enableAllButtons {
    NSArray *buttons = [self getAllButtons];   // censé contenir uniquement des instances de Button
    for (Button *button in buttons) {
        button->enabled = YES;
    }
} 

Imaginez maintenant qu'il y ait une erreur quelque part dans la logique de -getAllButtons et que vous obteniez également des instances de Label dans ce tableau - donc ces instances de la classe Label se verront affecter un ivar manquant. Le fait qui peut être surprenant est que -enableAllButtons ne plantera pas dans ce cas. Mais à ce stade, la structure interne de ces instances de Label est corrompue et cela causera un comportement indéfini et des plantages lorsqu'elles sont utilisées ailleurs.

Tout comme certains problèmes courants de gestion de mémoire (et en général - avec les pointeurs déréférencés) - ce genre de problèmes est difficile à trouver et à localiser - parce que l'apparition de l'erreur est généralement éloignée (en termes de temps, de code ou de flux d'application) du lieu causant l'erreur. Mais avec ce problème particulier, vous n'avez même pas d'outils pratiques (comme des analyseurs de fuites/zombies etc.) pour vous aider à localiser et à corriger - même lorsque vous apprenez comment le reproduire et pouvez facilement enquêter sur l'état erroné.

Évidemment, si vous utilisez @property (assign) BOOL enabled;, vous obtiendrez une exception d'exécution facile à diagnostiquer et à corriger dans -enableAllButtons.

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