151 votes

Pourquoi voudriez-vous utiliser un ivar ?

J'ai l'habitude de voir cette question posée dans l'autre sens, comme iOS: doit, chaque iVar vraiment bien? (et j'aime bbum est pour répondre à cette Q).

J'utilise les propriétés presque exclusivement dans mon code. Chaque si souvent, cependant, je travail avec un entrepreneur qui a été en développement sur iOS pour une longue période et est un jeu traditionnel programmeur. Il écrit le code qui déclare presque pas de propriétés que ce soit, et se penche sur ivars. Je suppose qu'il fait cela parce que 1.) il est utilisé depuis les propriétés n'étaient pas toujours d'exister jusqu'à ce que Objective-C 2.0 (Oct 07) 2.) pour un minimum de gain de performance de ne passant pas par un getter / setter.

Alors qu'il écrit le code qui n'a pas de fuite, je préfère encore lui d'utiliser les propriétés de plus de ivars. Nous en avons parlé et il a plus ou moins voit pas de raison d'utiliser les biens, puisque nous n'étions pas à l'aide de KVO et il a expérimenté avec prendre soin des problèmes de mémoire.

Ma question est plus... Pourquoi voudriez-vous jamais eu envie d'utiliser un ivar période expérimentés ou non. Est-il vraiment que beaucoup d'une différence de performance que l'utilisation d'un ivar serait-elle justifiée?

Aussi comme un point de clarification, je remplace les setters et getters que de besoin et d'utiliser le ivar, qui est en corrélation avec celle de la propriété à l'intérieur du getter / setter. Cependant, en dehors d'un getter / setter ou init, j'ai toujours utiliser l' self.myProperty de la syntaxe.


Edit 1

J'apprécie toutes les bonnes réponses. Celui que je voudrais aborder qui semble incorrect, c'est qu'avec un ivar vous obtenez l'encapsulation où avec une propriété que vous ne le faites pas. Il suffit de définir la propriété dans une classe de continuation. Cela permet de masquer la propriété des étrangers. Vous pouvez également déclarer la propriété readonly dans l'interface et de la redéfinir comme readwrite dans la mise en œuvre comme:

// readonly for outsiders
@property (nonatomic, copy, readonly) NSString * name;

et ont dans la classe de continuation:

// readwrite within this file
@property (nonatomic, copy) NSString * name;

Pour l'avoir complètement "privés" seule de le déclarer dans la classe de continuation.

100voto

justin Points 72871

L'Encapsulation

Si le ivar privée, les autres parties du programme ne pouvez pas obtenir aussi facilement. Avec une propriété déclarée, les gens intelligents peuvent accéder et mutent très facilement via les accesseurs.

Performance

Oui, cela peut faire une différence dans certains cas. Certains programmes ont des contraintes, où ils ne peuvent pas utiliser tout objc de messagerie dans certaines parties du programme (pensez en temps réel). Dans d'autres cas, vous pouvez accéder directement à la vitesse. Dans d'autres cas, c'est parce que objc de messagerie agit comme une optimisation de pare-feu. Enfin, il peut réduire votre nombre de références d'opérations et de minimiser l'utilisation maximale de la mémoire (si elle est faite correctement).

Non Triviaux Types

Exemple: Si vous avez une C++, l'accès direct est juste la meilleure approche parfois. Le type ne peut pas être copiable, ou il peut ne pas être facile à copier.

Le Multithreading

Beaucoup de vos ivars sont interdépendants. Vous devez vous assurer de l'intégrité de vos données dans le contexte multithread. Ainsi, vous pouvez préférer un accès direct à plusieurs membres dans les sections critiques. Si vous restez avec des accesseurs pour co-dépendant des données, de vos serrures doivent généralement être réentrant et vous aurez souvent à faire beaucoup plus d'acquisitions (beaucoup plus à la fois).

Programme De Justesse

Depuis les sous-classes peuvent remplacer n'importe quelle méthode, vous pouvez éventuellement voir il y a une différence sémantique entre l'écriture de l'interface par rapport à la gestion de votre état de manière appropriée. Accès Direct pour le programme d'exactitude est particulièrement commune dans les partiellement construit états -- dans votre initialiseurs et en dealloc, il est préférable d'utiliser l'accès direct. Vous pouvez également trouver cette commune dans la mise en œuvre d'un accesseur, une commodité constructeur, copy, mutableCopy, et d'archivage/de sérialisation des implémentations.

C'est aussi plus fréquentes que l'on se déplace à partir de la tout a un public readwrite accesseur l'état d'esprit de celui qui cache ses détails de mise en œuvre/de données. Parfois, vous devez correctement contourner les effets secondaires d'une sous-classe de " remplacement peut introduire dans le but de faire la bonne chose.

Taille Du Binaire

Déclarer tout readwrite par défaut est généralement le résultat dans de nombreuses méthodes accesseur vous n'avez jamais besoin, lorsque vous pensez à votre programme d'exécution pendant un moment. Donc, il va ajouter un peu de graisse de votre programme et les temps de chargement.

Réduire La Complexité

Dans certains cas, il est juste complètement inutile d'ajouter+type+de maintenir supplémentaires échafaudage pour une variable simple comme une private bool qui est écrit dans une méthode, et de lire dans un autre.


Ce n'est pas tout-à-dire grâce à des propriétés ou des accesseurs est mauvais - chacun a des avantages importants et les restrictions. Comme beaucoup de langages à objets et démarches de conception, vous devez également en faveur des accesseurs avec bonne visibilité dans ObjC. Il y aura des fois où vous avez besoin de s'écarter. Pour cette raison, je pense qu'il est souvent préférable de limiter l'accès direct à la mise en œuvre qui déclare la ivar (par exemple, déclarer @private).


re Edit 1:

La plupart d'entre nous ont mémorisé comment appeler un caché accesseur de manière dynamique (aussi longtemps que nous savons que le nom...). Pendant ce temps, la plupart d'entre nous ont pas mémorisé la manière d'accéder correctement ivars qui ne sont pas visibles (au-delà de KVC). La classe continuation aide, mais il n'introduire des vulnérabilités.

Cette solution de contournement est évident:

if ([obj respondsToSelector:(@selector(setName:)])
  [(id)obj setName:@"Al Paca"];

Maintenant, essayez avec un ivar seulement, et sans KVC.

76voto

Mecki Points 35351

Pour moi, c'est généralement de la performance. L'accès à une ivar d'un objet est aussi rapide que l'accès à une struct membre en C à l'aide d'un pointeur vers la mémoire contenant une telle structure. En fait, Objective-C, les objets sont fondamentalement C les structures situées dans la mémoire allouée dynamiquement. C'est généralement aussi vite que votre code peut obtenir, même pas la main optimisé le code d'assemblée peut être plus vite que ça. L'accès à une ivar par le biais d'une lecture/réglage implique un Objectif-C appel de la méthode, qui est beaucoup plus lent (au moins 3-4 fois) que "normale" C appel de fonction et même un C normale appel de fonction serait déjà plusieurs fois plus lent que l'accès à un struct membre comme décrit ci-dessus. De plus, selon les attributs de votre propriété, le setter/getter de la mise en œuvre généré par le compilateur peut impliquer un autre C appel de fonction pour les fonctions objc_getProperty/objc_setProperty, que ceux-ci doivent conserver/copier/autorelease les objets en tant que de besoin et en outre effectuer spinlocking pour les propriétés atomiques si nécessaire. Cela peut facilement devenir très cher, et je ne parle pas d'être 50% plus lent.

Essayons ceci:

CFAbsoluteTime cft;
unsigned const kRuns = 1000 * 1000 * 1000;

cft = CFAbsoluteTimeGetCurrent();
for (unsigned i = 0; i < kRuns; i++) {
    testIVar = i;
}
cft = CFAbsoluteTimeGetCurrent() - cft;
NSLog(@"1: %.1f picoseconds/run", (cft * 10000000000.0) / kRuns);

cft = CFAbsoluteTimeGetCurrent();
for (unsigned i = 0; i < kRuns; i++) {
    [self setTestIVar:i];
}
cft = CFAbsoluteTimeGetCurrent() - cft;
NSLog(@"2: %.1f picoseconds/run", (cft * 10000000000.0) / kRuns);

Sortie:

1: 23.0 picoseconds/run
2: 98.4 picoseconds/run

C'est 4.28 fois plus lent et que c'était un non-atomique primitive int, à peu près le meilleur des cas, la plupart des autres cas sont encore pire. Donc, si vous pouvez vivre avec le fait que chaque ivar accès est 4 à 5 fois plus lente que ce qu'elle pourrait être, en utilisant les propriétés est très bien (du moins quand il s'agit de la performance), cependant, il ya beaucoup de situations où une telle chute des performances est totalement inacceptable. Si votre CPU descend à moins de 25% de la performance au cours de la nuit, vous auriez sûrement pas être très heureux à ce sujet.

Il est similaire à la KVO: je me souviens d'un gars qui a écrit un 3D OpenGL jeu à l'aide de l'Obj-C et KVO et à la fin il a demandé pourquoi il était si lent. Eh bien, il s'est avéré que seule la définition des propriétés à l'aide de KVO utilisé comme PROCESSEUR de temps que tous les OpenGL 3D et jeu de logique d'ensemble du code. La vitesse de l'application augmenté de plus de 200% après tous KVO de codage a été éliminé de la critique chemins de code.

Perdre un centime ne sera pas vous faire beaucoup plus pauvres, la perte d'un cent une seconde vous coûtera $864 quotidien et de perdre 1000 cents un second fera la plupart des gens aller a éclaté dans la mesure moins d'une heure. Tout dépend de la fréquence des getters/setters sont appelés (un jour, une minute ou une seconde). Depuis que j'ai souvent ne peut pas dire à l'avance, par exemple lors de la rédaction d'un cadre et de ne pas être sûr de savoir comment les autres programmeurs vont l'utiliser, je préfère toujours aller pour un maximum de performances, à moins que j'ai une très bonne raison de ne pas le faire.

9voto

DarkDust Points 47584

La raison la plus importante est de la programmation orientée objet concept de se cacher de l'information: Si vous exposez tout via les propriétés et donc permettent de faire des objets externes à coup d'oeil à un autre objet lui-même, puis vous allez faire usage de ces internes et donc compliquer la modification de la mise en œuvre.

"Une performance minimale" gain peut résumer vite et puis devenir un problème. Je sais, par expérience, je travaille sur une application qui prend vraiment les iDevices à leurs limites, et il nous faut donc éviter les appels de méthode (bien sûr uniquement lorsque cela est raisonnablement possible). Pour de l'aide avec cet objectif, nous sommes également en évitant la syntaxe à point, car il rend difficile de voir le nombre d'appels de méthode à première vue: par exemple, combien d'appels de méthode en fait l'expression self.image.size.width trigger? En revanche, vous pouvez immédiatement dire avec [[self image] size].width.

Aussi, avec un bon ivar de nommage, KVO est possible sans propriétés (autant que je me souvienne, je ne suis pas un KVO expert).

9voto

Jano Points 37593

La sémantique

  • Ce @property peut exprimer ce qui ivars ne peut pas: nonatomic et copy.
  • Ce ivars peut exprimer qu' @propertyne peut pas:
    • @protected: public sur les sous-classes, privée à l'extérieur.
    • @package: public sur les cadres sur 64 bits, privée à l'extérieur. Même en tant que @public sur 32 bits. Voir Apple 64 bits de Classe et d'Instance de la Variable de Contrôle d'Accès.
    • Les tournois de qualification. Par exemple, des tableaux de solides références de l'objet: id __strong *_objs.

Performance

Histoire courte: ivars sont plus rapides, mais il n'a pas d'importance pour la plupart des utilisations. nonatomic propriétés ne pas utiliser des verrous, mais direct ivar est plus rapide car il ignore les accesseurs d'appel. Pour plus de détails lire la suite e-mail à partir de lists.apple.com.

Subject: Re: when do you use properties vs. ivars?
From: John McCall <email@hidden>
Date: Sun, 17 Mar 2013 15:10:46 -0700

Propriétés affecter les performances de beaucoup de façons:

  1. Comme déjà discuté, l'envoi d'un message à faire un load/store est plus lent que le load/store inline.

  2. L'envoi d'un message à faire un load/store est également tout à fait un peu plus de code qui doit être gardé à l'i-cache: même si les getter/setter ajouté à zéro les instructions supplémentaires au-delà de l'load/store, il y en avait un solide demi-douzaine d'instructions supplémentaires de l'appelant pour configurer le message envoyer et gérer le résultat.

  3. Envoyer un message forces d'entrée pour ce sélecteur pour être maintenu dans la méthode de cache, et que la mémoire en général autour de bâtons dans d-cache. Cela augmente le temps de lancement, augmente la mémoire statique l'utilisation de votre application, et rend les changements de contexte de plus en plus douloureux. Depuis le méthode de cache est spécifique à la dynamique de la classe d'un objet, ce problème augmente avec l'utilisation KVO.

  4. Envoyer un message forces toutes les valeurs de la fonction d'être renversé à la pile (ou de conserver dans callee-save registres, ce qui signifie simplement renverser à un autre moment).

  5. L'envoi d' un message peut avoir des effets secondaires et, par conséquent,

    • les forces de l'compilateur pour réinitialiser l'ensemble de ses hypothèses au sujet de la non-local de la mémoire
    • ne peut pas être hissé, coulé, re-commandés, fusionné, ou éliminés.

  6. Dans l'ARC, le résultat d'un message envoyer obtiendrez toujours conservé, soit par le destinataire de l'appel ou de l'appelant, même pour +0 retourne: même si le méthode de ne pas retenir/autorelease de son résultat, l'appelant ne sais pas que et a tenter de prendre des mesures pour empêcher la suite de l'obtention de autoreleased. Cela ne peut jamais être supprimée, parce que les message envoie sont pas de manière statique analysable.

  7. Dans l'ARC, car une méthode de définition généralement tire son argument est de +0, il n'y a aucun moyen de "transfert" a retenir de cet objet (qui, comme discuté ci-dessus, l'ARC a généralement) dans le ivar, de sorte que la valeur a généralement pour obtenir de conserver/publié deux fois.

Cela ne signifie pas qu'ils sont toujours mauvais, bien sûr - il y a un beaucoup de bonnes raisons d'utiliser les propriétés. Il suffit de garder à l'esprit que, comme de nombreuses autres fonctionnalités de langage, ils ne sont pas gratuits.


Jean.

5voto

dreamlax Points 47152

Compatibilité en arrière était un facteur pour moi. Je ne pouvais pas utiliser toutes les fonctionnalités d’Objective-C 2.0 parce que je développais des pilotes imprimante et logiciel qui devaient travailler sur Mac OS X 10.3, dans le cadre d’une exigence. Je sais que votre question semblée ciblée autour d’iOS, mais j’ai pensé que je partagerais toujours mes raisons pour ne pas utiliser les propriétés.

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