Que signifient les termes "atomique" et "non atomique" dans les déclarations de propriétés ?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
Quelle est la différence opérationnelle entre les trois ?
Cela est expliqué dans la [documentation][1] d'Apple, mais vous trouverez ci-dessous quelques exemples de ce qui se passe réellement.
Notez qu'il n'existe pas de mot-clé " atomique ". Si vous ne spécifiez pas " non atomique ", la propriété est atomique, mais si vous spécifiez " atomique " explicitement, une erreur se produira ;
Si vous ne spécifiez pas "nonatomic" ;, alors la propriété est atomique, mais vous pouvez toujours spécifier "atomic" ; explicitement dans les versions récentes si vous le souhaitez.
//@property(nonatomic, retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
return userName;
}
- (void) setUserName:(UITextField *)userName_ {
[userName_ retain];
[userName release];
userName = userName_;
}
Maintenant, la variante atomique est un peu plus compliquée :
//@property(retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
UITextField *retval = nil;
@synchronized(self) {
retval = [[userName retain] autorelease];
}
return retval;
}
- (void) setUserName:(UITextField *)userName_ {
@synchronized(self) {
[userName_ retain];
[userName release];
userName = userName_;
}
}
Fondamentalement, la version atomique doit prendre un verrou afin de garantir la sécurité des threads, et augmente également le nombre de références sur l'objet (et le nombre d'autorelease pour l'équilibrer) afin que l'objet soit garanti d'exister pour l'appelant, sinon il y a une condition de course potentielle si un autre thread définit la valeur, provoquant la chute du nombre de références à 0.
Il y a en fait un grand nombre de variantes différentes de la façon dont ces choses fonctionnent selon que les propriétés sont des valeurs scalaires ou des objets, et comment retain, copy, readonly, nonatomic, etc interagissent. En général, les synthétiseurs de propriétés savent comment faire la "bonne chose" pour toutes les combinaisons.
Atomique garantit que l'accès à la propriété sera effectué de manière atomique. Par exemple, il renvoie toujours un objet complètement initialisé, tout get/set d'une propriété sur un thread doit être terminé avant qu'un autre puisse y accéder.
Si vous imaginez la fonction suivante se produisant sur deux threads à la fois, vous pouvez comprendre pourquoi les résultats ne seraient pas jolis.
-(void) setName:(NSString*)string
{
if (name)
{
[name release];
// what happens if the second thread jumps in now !?
// name may be deleted, but our 'name' variable is still set!
name = nil;
}
...
}
Pros : Le retour d'objets entièrement initialisés à chaque fois en fait le meilleur choix en cas de multithreading.
Inconvénients : Les performances sont affectées, l'exécution est un peu plus lente.
Contrairement à Atomic, elle ne garantit pas le retour d'un objet entièrement initialisé à chaque fois.
Avantages : Exécution extrêmement rapide.
Inconvénients : Chances de garbage value en cas de multi-threading.
La réponse la plus facile d'abord : Il n’y a aucune différence entre vos deux seconds exemples. Par défaut, les accesseurs de propriétés sont atomiques.
Les accesseurs atomiques dans un environnement sans ramassage des ordures (c'est-à-dire lors de l'utilisation de retain/release/autorelease) utiliseront un verrou pour s'assurer qu'un autre thread n'interfère pas avec la définition ou l'obtention correcte de la valeur.
Consultez la section " ;[Performance and Threading][1]" ; de la documentation Objective-C 2.0 d'Apple pour de plus amples informations et pour d'autres considérations relatives à la création d'applications multithread.
[1] : http://www.scribd.com/doc/121014348/89/Performance-and-Threading "Performance and Threading" ;