@property conserve, attribue, copie, non anatomique dans Objective-C

214

En tant que personne qui est nouvelle à Objective-C, quelqu'un peut-il me donner un aperçu de la conservation, de l'attribution, de la copie et de toutes les autres qui me manquent, qui suivent la directive @property? Que font-ils et pourquoi voudrais-je les utiliser les uns par rapport aux autres?

Mark Reid
la source
1
Le nom d'Apple pour ceux-ci est "attributs" ou "attributs de propriété"
nevan king

Réponses:

274

L'article lié par MrMage ne fonctionne plus. Voici donc ce que j'ai appris lors de mon (très) court codage en Objective-C:

non atomique vs atomique - "atomique" est la valeur par défaut. Utilisez toujours "non anatomique". Je ne sais pas pourquoi, mais le livre que j'ai lu dit qu'il y a "rarement une raison" d'utiliser "atomique". (BTW: Le livre que j'ai lu est le livre BNR "Programmation iOS".)

readwrite vs readonly - "readwrite" est la valeur par défaut. Lorsque vous @synthétisez, un getter et un setter seront créés pour vous. Si vous utilisez "lecture seule", aucun setter ne sera créé. Utilisez-le pour une valeur que vous ne souhaitez pas modifier après l'instanciation de l'objet.

conserver vs copier vs assigner

  • "assigner" est la valeur par défaut. Dans le setter créé par @synthesize, la valeur sera simplement affectée à l'attribut. Ma compréhension est que "assigner" devrait être utilisé pour les attributs non pointeurs.
  • "conserver" est nécessaire lorsque l'attribut est un pointeur vers un objet. Le setter généré par @synthesize conservera (aka ajouter un nombre de retenues) l'objet. Vous devrez libérer l'objet lorsque vous en aurez terminé avec lui.
  • "copie" est nécessaire lorsque l'objet est modifiable. Utilisez-le si vous avez besoin de la valeur de l'objet telle qu'elle est en ce moment et que vous ne souhaitez pas que cette valeur reflète les modifications apportées par d'autres propriétaires de l'objet. Vous devrez libérer l'objet lorsque vous en aurez terminé car vous conservez la copie.
Blamdarot
la source
@Blamdarot - dois-je également le publier avec ARC
Dejell
10
@Odelya - Non. Si vous publiez en utilisant ARC, je pense que vous obtiendrez une erreur de compilation.
Blamdarot
53
«Toujours utiliser non anatomique» est un mauvais conseil. Vous devez savoir à quoi vous renoncez lorsque vous utilisez des produits non anatomiques.
Jesse Rusak
7
D'accord. En particulier, beaucoup de gens ne semblent pas savoir que les valeurs non anatomiques ne sont pas autorisées par le getter. non anatomique est souvent approprié, mais la programmation culte du fret l'est rarement.
Catfish_Man
9
Conseiller de quitter la valeur par défaut atomicest tout aussi mauvais que conseiller nonatomic. Aucun des deux choix n'est "correct", les concepteurs de langage ont donc opté pour la plus sûre des deux solutions. En fait, nonatomicc'est généralement le meilleur choix car il omet les verrous de fil extrêmement coûteux. La seule raison d'utiliser atomicest si votre propriété peut être définie à partir de plusieurs threads (auquel cas l'omettre peut entraîner une libération excessive ou une fuite).
Adam Kaplan
295

Avant de connaître les attributs de @property, vous devez savoir à quoi sert @property.

  • @property offre un moyen de définir les informations qu'une classe est destinée à encapsuler. Si vous déclarez un objet / variable à l'aide de @property , cet objet / variable sera accessible aux autres classes qui importent sa classe.

  • Si vous déclarez un objet en utilisant @property dans le fichier d'en-tête, vous devez alors le synthétiser en utilisant @synthesize dans le fichier d'implémentation. Cela rend l'objet conforme KVC . Par défaut, le compilateur synthétisera les méthodes d'accesseur pour cet objet.

  • Les méthodes d'accesseur sont: setter et getter.

Exemple: .h

@interface XYZClass : NSObject
@property (nonatomic, retain) NSString *name;
@end

.m

@implementation XYZClass
@synthesize name;
@end

Le compilateur va maintenant synthétiser les méthodes d'accesseur pour le nom .

XYZClass *obj=[[XYZClass alloc]init];
NSString *name1=[obj name]; // get 'name'
[obj setName:@"liza"]; // first letter of 'name' becomes capital in setter method
  • Liste des attributs de @property

    atomique, non atomique, conserver, copier, lecture seule, lecture-écriture, assigner, fort, getter = méthode, setter = méthode, unsafe_unretained

  • atomic est le comportement par défaut. Si un objet est déclaré atomique, il devient thread-safe. Thread-safe signifie qu'à la fois un seul thread d'une instance particulière de cette classe peut avoir le contrôle sur cet objet.

Si le thread exécute la méthode getter, aucun autre thread ne peut exécuter la méthode setter sur cet objet. C'est lent.

@property NSString *name; //by default atomic`
@property (atomic)NSString *name; // explicitly declared atomic`
  • nonatomic n'est pas thread-safe. Vous pouvez utiliser l'attribut de propriété nonatomique pour spécifier que les accesseurs synthétisés définissent ou retournent simplement une valeur directement, sans aucune garantie de ce qui se passe si cette même valeur est accédée simultanément à partir de différents threads.

Pour cette raison, il est plus rapide d'accéder à une propriété non atomique qu'à une propriété atomique.

@property (nonatomic)NSString *name;   
  • conserver est requis lorsque l'attribut est un pointeur sur un objet.

La méthode de définition augmentera le nombre de rétentions de l'objet, de sorte qu'il occupera de la mémoire dans le pool de libération automatique.

@property (retain)NSString *name;
  • copier Si vous utilisez la copie, vous ne pouvez pas utiliser la conservation. L'utilisation d'une instance de copie de la classe contiendra sa propre copie.

Même si une chaîne mutable est définie et modifiée par la suite, l'instance capture la valeur qu'elle a au moment où elle est définie. Aucune méthode setter et getter ne sera synthétisée.

@property (copy) NSString *name;

maintenant,

NSMutableString *nameString = [NSMutableString stringWithString:@"Liza"];    
xyzObj.name = nameString;    
[nameString appendString:@"Pizza"]; 

le nom ne sera pas affecté.

  • en lecture seule Si vous ne souhaitez pas autoriser la modification de la propriété via la méthode setter, vous pouvez déclarer la propriété en lecture seule.

Le compilateur va générer un getter, mais pas un setter.

@property (readonly) NSString *name;
  • readwrite est le comportement par défaut. Vous n'avez pas besoin de spécifier explicitement l'attribut readwrite.

C'est l'opposé de readonly.

@property (readwrite) NSString *name;
  • assign va générer un setter qui affecte directement la valeur à la variable d'instance, plutôt que de la copier ou de la conserver. C'est le meilleur pour les types primitifs comme NSInteger et CGFloat, ou les objets que vous ne possédez pas directement, tels que les délégués.

Gardez à l'esprit que la conservation et l'attribution sont essentiellement interchangeables lorsque la récupération de place est activée.

@property (assign) NSInteger year;
  • fort est un remplacement pour conserver.

Il est livré avec ARC.

@property (nonatomic, strong) AVPlayer *player; 
  • getter = method Si vous souhaitez utiliser un nom différent pour une méthode getter, il est possible de spécifier un nom personnalisé en ajoutant des attributs à la propriété.

Dans le cas des propriétés booléennes (propriétés qui ont une valeur OUI ou NON), il est habituel que la méthode getter commence par le mot «est»

@property (getter=isFinished) BOOL finished;
  • setter = method Si vous souhaitez utiliser un nom différent pour une méthode setter, il est possible de spécifier un nom personnalisé en ajoutant des attributs à la propriété.

La méthode doit se terminer par deux points.

@property(setter = boolBool:) BOOL finished;
  • unsafe_unretained Il existe quelques classes dans Cocoa et Cocoa Touch qui ne prennent pas encore en charge les références faibles, ce qui signifie que vous ne pouvez pas déclarer une propriété faible ou une variable locale faible pour en garder la trace. Ces classes incluent NSTextView, NSFont et NSColorSpace, etc. Si vous devez utiliser une référence faible à l'une de ces classes, vous devez utiliser une référence non sécurisée.

Une référence non sécurisée est similaire à une référence faible en ce qu'elle ne maintient pas en vie son objet associé, mais elle ne sera pas définie sur nil si l'objet de destination est désalloué.

@property (unsafe_unretained) NSObject *unsafeProperty;

Si vous devez spécifier plusieurs attributs, incluez-les simplement en tant que liste séparée par des virgules, comme ceci:

@property (readonly, getter=isFinished) BOOL finished;
liza
la source
De plus, faible signifie qu'il n'y a pas de compte de référence au référencé à l'objet, mais qu'il est référencé du tout ou pas référencé du tout. Un peu comme "oui, quelque chose m'a référencé" contre "9 références à moi existent" (ce qui est fort).
Alex Zavatone
6
Ignorez la ligne dans la réponse concernant le garbage collection, car le garbage collection est déconseillé sous Mac OS X et inexistant dans iOS selon la documentation Apple .
Basil Bourque
4
"Remarque: l'atomicité des propriétés n'est pas synonyme de sécurité des threads d'un objet." - depuis developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7
1
"Si vous déclarez un objet en utilisant @propertydans le fichier d'en-tête, alors vous devez le synthétiser en utilisant @synthesizedans le fichier d'implémentation." Pas toujours. Par exemple, "Par défaut, une readwritepropriété sera soutenue par une variable d'instance, qui sera à nouveau synthétisée automatiquement par le compilateur." Du doc .
Franklin Yu
4
@liza C'est une excellente réponse. Pourquoi n'est-ce pas la réponse acceptée. Elle donne une explication bien plus approfondie que la réponse actuellement acceptée. Je ne comprends pas parfois StackOverflow?
Charles Robertson
149

Après avoir lu de nombreux articles, j'ai décidé de rassembler toutes les informations sur les attributs:

  1. atomique // par défaut
  2. non anatomique
  3. fort = conserver // par défaut
  4. faible = unsafe_unretained
  5. conserver
  6. assign // par défaut
  7. unsafe_unretained
  8. copie
  9. lecture seulement
  10. readwrite // par défaut

Vous trouverez ci-dessous un lien vers l'article détaillé où vous pouvez trouver ces attributs.

Un grand merci à toutes les personnes qui donnent les meilleures réponses ici !!

Attributs de propriétés variables ou modificateurs dans iOS

Voici l'exemple de description de l'article

  1. atomic -Atomic signifie qu'un seul thread accède à la variable (type statique). -Atomic est thread-safe. -mais il est lent dans les performances -atomique est le comportement par défaut -Les accesseurs atomiques dans un environnement non récupéré (c'est-à-dire lors de l'utilisation de retenir / libérer / libérer automatiquement) utiliseront un verrou pour s'assurer qu'un autre thread n'interfère pas avec le bon réglage / obtention de la valeur. -il n'est pas réellement un mot-clé.

Exemple :

@property (retain) NSString *name;

@synthesize name;
  1. nonatomic -Nonatomic signifie plusieurs threads accèdent à la variable (type dynamique). -Nonatomic est thread dangereux. -mais il est rapide dans les performances -Nonatomic n'est PAS un comportement par défaut, nous devons ajouter un mot-clé nonatomic dans l'attribut de propriété. -il peut entraîner un comportement inattendu, lorsque deux processus différents (threads) accèdent à la même variable en même temps.

Exemple:

@property (nonatomic, retain) NSString *name;

@synthesize name;

Explique:

Supposons qu'il existe une propriété de chaîne atomique appelée "nom", et si vous appelez [self setName: @ "A"] à partir du thread A, appelez [self setName: @ "B"] à partir du thread B, et appelez [self name] à partir de thread C, alors toutes les opérations sur un thread différent seront effectuées en série, ce qui signifie que si un thread exécute setter ou getter, les autres threads attendront. Cela rend la propriété "nom" accessible en lecture / écriture, mais si un autre thread D appelle [libération de nom] simultanément, cette opération peut produire un plantage car aucun appel setter / getter n'est impliqué ici. Ce qui signifie qu'un objet est protégé en lecture / écriture (ATOMIQUE) mais pas en thread car un autre thread peut envoyer simultanément tout type de messages à l'objet. Le développeur doit garantir la sécurité des threads pour ces objets.

Si la propriété "nom" n'était pas atomique, alors tous les threads de l'exemple ci-dessus - A, B, C et D s'exécuteront simultanément produisant tout résultat imprévisible. En cas d'atomique, l'un de A, B ou C s'exécutera en premier mais D peut toujours s'exécuter en parallèle.

  1. fort (iOS4 = retenir) -il dit "garder cela dans le tas jusqu'à ce que je ne le pointe plus" -en d'autres termes "je suis le propriétaire, vous ne pouvez pas désallouer ceci avant de viser bien avec le même que conserver" - Vous utilisez fort uniquement si vous devez conserver l'objet. -Par défaut, toutes les variables d'instance et les variables locales sont des pointeurs puissants. -Nous utilisons généralement strong pour UIViewControllers (les parents de l'élément d'interface utilisateur) -strong est utilisé avec ARC et il vous aide essentiellement, en n'ayant pas à vous soucier du nombre de conserver d'un objet. ARC le libère automatiquement pour vous lorsque vous en avez terminé. L'utilisation du mot clé strong signifie que vous êtes propriétaire de l'objet.

Exemple:

@property (strong, nonatomic) ViewController *viewController;

@synthesize viewController;
  1. faible (iOS4 = unsafe_unretained) - il dit "garder cela aussi longtemps que quelqu'un le pointe fortement" - la même chose que assigner, pas de conserver ou de libérer - Une référence "faible" est une référence que vous ne conservez pas. -Nous utilisons généralement faible pour les IBOutlets (UIViewController Childs). Cela fonctionne parce que l'objet enfant ne doit exister que tant que l'objet parent le fait. -une référence faible est une référence qui ne protège pas l'objet référencé de la collecte par un garbage collector. -Le faible est essentiellement assigné, une propriété non retenue. Sauf lorsque l'objet est désalloué, le pointeur faible est automatiquement défini sur zéro

Exemple :

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

@synthesize myButton;

Explication forte et faible, merci à BJ Homer :

Imaginez que notre objet soit un chien et que le chien veuille s'enfuir (être désalloué). Les pointeurs puissants sont comme une laisse sur le chien. Tant que la laisse est attachée au chien, le chien ne s'enfuira pas. Si cinq personnes attachent leur laisse à un chien (cinq pointeurs solides vers un objet), le chien ne s'enfuira pas tant que les cinq laisses ne seront pas détachées. Les pointeurs faibles, par contre, sont comme des petits enfants qui pointent vers le chien et disent «Regardez! Tant que le chien est toujours en laisse, les petits enfants peuvent toujours voir le chien et ils le pointeront toujours. Dès que toutes les laisses sont détachées, le chien s'enfuit, peu importe le nombre de petits enfants qui le désignent. Dès que le dernier pointeur fort (laisse) ne pointe plus sur un objet, l'objet sera désalloué et tous les pointeurs faibles seront mis à zéro. Lorsque nous utilisons faible? La seule fois que vous voudriez utiliser faible, c'est si vous voulez éviter les cycles de rétention (par exemple, le parent retient l'enfant et l'enfant conserve le parent afin qu'aucun des deux ne soit jamais libéré).

  1. retenir = fort -il est conservé, l'ancienne valeur est libérée et elle est affectée -retain spécifie que la nouvelle valeur doit être envoyée -retain lors de l'affectation et l'ancienne valeur envoyée -release -retain est la même que forte. -apple indique que si vous écrivez conserver, il sera automatiquement converti / fonctionnera comme fort uniquement. -les méthodes comme "alloc" incluent un "retenir" implicite

Exemple:

@property (nonatomic, retain) NSString *name;

@synthesize name;
  1. assign -assign est la valeur par défaut et effectue simplement une assignation de variable -assign est un attribut de propriété qui indique au compilateur comment synthétiser l'implémentation du setter de la propriété -J'utiliserais assign pour les propriétés primitives C et faible pour les références faibles aux objets Objective-C.

Exemple:

@property (nonatomic, assign) NSString *address;

@synthesize address;
  1. unsafe_unretained

    -unsafe_unretained est un qualificatif de propriété qui indique à ARC comment insérer des appels de retenue / libération -unsafe_unretained est la version ARC de assign.

Exemple:

@property (nonatomic, unsafe_unretained) NSString *nickName;

@synthesize nickName;
  1. copie-copie est requise lorsque l'objet est modifiable. -copy spécifie que la nouvelle valeur doit être envoyée -copy lors de l'affectation et l'ancienne valeur envoyée -release. -copy est comme retenue renvoie un objet que vous devez explicitement libérer (par exemple, dans dealloc) dans des environnements non récupérés. -si vous utilisez la copie, vous devez toujours la libérer dans dealloc. -Utilisez ceci si vous avez besoin de la valeur de l'objet telle qu'elle est en ce moment et que vous ne voulez pas que cette valeur reflète les modifications apportées par d'autres propriétaires de l'objet. Vous devrez libérer l'objet lorsque vous en aurez terminé car vous conservez la copie.

Exemple:

@property (nonatomic, copy) NSArray *myArray;

@synthesize myArray;
swiftBoy
la source
2
Je pense qu'après l'arc, retenir n'est plus utilisé.
mert
1
la liste complète manque 2 éléments d'option: setter et getter, qui sont également les seules options qui nécessitent un argument.
Scott Chu
fort ou conserver est par défaut pour le type d'objet uniquement. Il ne peut pas être utilisé pour des types primitifs.
Saleh Enam Shohag
9

La propriété atomique est accessible par un seul thread à la fois. Il est thread-safe . La valeur par défaut est atomique. Veuillez noter qu'il n'y a pas de mot-clé atomique

Nonatomic moyen filetage multiple peut accéder à l'élément .Il est dangereux de fil

Il faut donc être très prudent lors de l'utilisation atomique .Comme cela affecte les performances de votre code

Kannan Prasad
la source
3
"Remarque: l'atomicité des propriétés n'est pas synonyme de sécurité des threads d'un objet." de developer.apple.com/library/mac/documentation/Cocoa/Conceptual/…
jk7