Was bedeuten "atomar" und "nichtatomar" in Eigenschaftsdeklarationen?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
Was ist der operative Unterschied zwischen diesen drei?
Dies wird in der Dokumentation von Apple erklärt, aber im Folgenden finden Sie einige Beispiele dafür, was tatsächlich passiert.
Beachten Sie, dass es kein Schlüsselwort "atomic" gibt. Wenn Sie nicht "nonatomic" angeben, ist die Eigenschaft atomar, aber die explizite Angabe von "atomic" führt zu einem Fehler.
Wenn Sie "nonatomic" nicht angeben, ist die Eigenschaft atomar, aber Sie können "atomic" in neueren Versionen immer noch explizit angeben, wenn Sie das möchten.
//@property(nonatomic, retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
return userName;
}
- (void) setUserName:(UITextField *)userName_ {
[userName_ retain];
[userName release];
userName = userName_;
}
Die atomare Variante ist ein wenig komplizierter:
//@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_;
}
}
Grundsätzlich muss die atomare Version eine Sperre nehmen, um die Threadsicherheit zu gewährleisten, und erhöht außerdem den Ref-Count des Objekts (und den Autorelease-Count, um ihn auszugleichen), so dass das Objekt für den Aufrufer garantiert existiert, andernfalls gibt es eine potenzielle Race-Condition, wenn ein anderer Thread den Wert setzt, wodurch der Ref-Count auf 0 fällt.
Es gibt tatsächlich eine große Anzahl von verschiedenen Varianten, wie diese Dinge funktionieren, je nachdem, ob die Eigenschaften skalare Werte oder Objekte sind, und wie retain, copy, readonly, nonatomic, etc. interagieren. Im Allgemeinen wissen die Eigenschaftssynthetisierer einfach, wie sie das "Richtige" für alle Kombinationen tun.
Atomic garantiert, dass der Zugriff auf die Eigenschaft auf atomare Weise erfolgt. So wird z. B. immer ein vollständig initialisiertes Objekt zurückgegeben, und jedes Get/Set einer Eigenschaft auf einem Thread muss abgeschlossen sein, bevor ein anderer darauf zugreifen kann.
Wenn Sie sich vorstellen, dass die folgende Funktion auf zwei Threads gleichzeitig abläuft, können Sie sehen, warum die Ergebnisse nicht schön wären.
-(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 : Da jedes Mal vollständig initialisierte Objekte zurückgegeben werden, ist sie die beste Wahl im Falle von Multi-Threading.
Cons : Leistungseinbußen, macht die Ausführung ein wenig langsamer
Im Gegensatz zu Atomic wird nicht sichergestellt, dass jedes Mal ein vollständig initialisiertes Objekt zurückgegeben wird.
Pros : Äußerst schnelle Ausführung.
Gegensätze : Wahrscheinlichkeit von Garbage-Werten im Falle von Multi-Threading.
Die einfachste Antwort zuerst: Es gibt keinen Unterschied zwischen Ihren zweiten beiden Beispielen. Standardmäßig sind Property Accessors atomar.
Atomare Accessors in einer nicht Garbage-Collection-Umgebung (d.h. bei Verwendung von retain/release/autorelease) verwenden eine Sperre, um sicherzustellen, dass ein anderer Thread das korrekte Setzen/Holen des Wertes nicht beeinträchtigt.
Im Abschnitt "Performance and Threading" der Objective-C 2.0-Dokumentation von Apple finden Sie weitere Informationen und andere Überlegungen zur Erstellung von Anwendungen mit mehreren Threads.