41 votes

Pourquoi ne devrais-je pas utiliser les accesseurs Objective C 2.0 dans init/dealloc?

Dans @mmalc's réponse à cette question, il déclare que "En général, vous ne devriez pas utiliser les méthodes d'accesseur dans dealloc (ou init)." Pourquoi mmalc dit-il cela?

Les seules raisons que je peux vraiment penser sont la performance et d'éviter les effets secondaires inconnus des setters @dynamic.

Discussion?

29voto

Andrew Grant Points 35305

C'est essentiellement un guide pour minimiser le potentiel de bugs.

Dans ce cas, il y a la possibilité que votre setter/getter puisse faire involontairement des suppositions directes ou indirectes sur l'état de l'objet. Ces suppositions pourraient poser problème lorsque l'objet est en train d'être configuré ou détruit.

Par exemple, dans le code ci-dessous, l'observateur ne sait pas que 'Example' est en train d'être détruit et pourrait supposer que d'autres propriétés, qui ont déjà été libérées, sont valides.

(On pourrait arguer que votre objet devrait supprimer tous les observateurs avant de se détruire, ce qui serait une bonne pratique, et un autre guide pour prévenir les problèmes involontaires).

@implementation Example

-(void) setFoo:(Foo*)foo
{
   _foo = foo;
  [_observer onPropertyChange:self object:foo];
}

-(void) dealloc
{
   ...
   self.foo = nil;
}

@end

19voto

Louis Gerbarg Points 33025

Il s'agit avant tout d'utiliser un code idiomatiquement cohérent. Si vous modèlez tout votre code de manière appropriée, il existe des ensembles de règles garantissant que l'utilisation d'un accesseur dans init/dealloc est sûre.

Le gros problème est que (comme l'a dit mmalc) le code qui définit l'état par défaut des propriétés ne devrait pas passer par un accesseur car cela entraîne toutes sortes de problèmes désagréables. Le hic, c'est qu'il n'y a aucune raison pour que init initialise l'état par défaut d'une propriété. Pour plusieurs raisons, je suis passé à des accesseurs qui s'initialisent eux-mêmes, comme dans le simple exemple ci-dessous :

- (NSMutableDictionary *) myMutableDict {
    if (!myMutableDict) {
        myMutableDict = [[NSMutableDictionary alloc] init];
    }

    return myMutableDict;
}

Ce style d'initialisation de propriété permet de reporter beaucoup de code d'initialisation qui n'est peut-être pas réellement nécessaire. Dans le cas ci-dessus, init n'est pas responsable de l'initialisation de l'état des propriétés, et il est tout à fait sûr (voire nécessaire) d'utiliser les accesseurs dans la méthode init.

Admettons que cela impose des restrictions supplémentaires à votre code, par exemple, les sous-classes avec des accesseurs personnalisés pour une propriété dans la superclasse doivent appeler l'accesseur de la superclasse, mais ces restrictions ne sont pas excessives par rapport à diverses autres restrictions courantes dans Cocoa.

15voto

mmalc Points 7663

Vous avez répondu à votre propre question:

  1. La performance peut être une raison parfaitement adéquate en elle-même (surtout si vos accesseurs sont atomiques).
  2. Vous devriez éviter tout effet secondaire que peuvent avoir les accesseurs.

Le dernier point est particulièrement important si votre classe peut être sous-classée.

Cependant, il n'est pas clair pourquoi ceci est spécifiquement adressé aux accesseurs de Objective-C 2 ? Les mêmes principes s'appliquent que vous utilisiez des propriétés déclarées ou que vous écriviez vos accesseurs vous-même.

2voto

Zaph Points 40557

Il se peut que le setter ait une logique qui doit s'exécuter ou peut-être que l'implémentation a utilisé un ivar avec un nom différent du getter / setter ou peut-être deux ivars qui doivent être libérés et / ou avoir leur valeur définie sur nil. La seule façon sûre est d'appeler le setter. Il incombe au setter d'être écrit de manière à ce que des effets secondaires indésirables ne se produisent pas lorsqu'il est appelé pendant l'initialisation ou la libération.

Extrait de "Cocoa Design Patterns", Buck, Yacktman, pp 115 : "... il n'y a pas d'alternative pratique à l'utilisation des accesseurs lorsque vous utilisez des variables d'instance synthétisées avec le runtime Objective-C moderne ou ..."

0voto

FeifanZ Points 9348

En fait, pour une classe qui vient et part assez souvent (comme un contrôleur de vue de détail), vous voulez utiliser l'accessoir dans l'init ; sinon, vous pourriez finir par libérer une valeur dans viewDidUnload que vous essayez d'accéder plus tard (ils le montrent dans CS193P...)

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