What's the difference between the atomic and nonatomic attributes?

Viewed 519267

What do atomic and nonatomic mean in property declarations?

@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;

What is the operational difference between these three?

27 Answers

The last two are identical; "atomic" is the default behavior (note that it is not actually a keyword; it is specified only by the absence of nonatomic -- atomic was added as a keyword in recent versions of llvm/clang).

Assuming that you are @synthesizing the method implementations, atomic vs. non-atomic changes the generated code. If you are writing your own setter/getters, atomic/nonatomic/retain/assign/copy are merely advisory. (Note: @synthesize is now the default behavior in recent versions of LLVM. There is also no need to declare instance variables; they will be synthesized automatically, too, and will have an _ prepended to their name to prevent accidental direct access).

With "atomic", the synthesized setter/getter will ensure that a whole value is always returned from the getter or set by the setter, regardless of setter activity on any other thread. That is, if thread A is in the middle of the getter while thread B calls the setter, an actual viable value -- an autoreleased object, most likely -- will be returned to the caller in A.

In nonatomic, no such guarantees are made. Thus, nonatomic is considerably faster than "atomic".

What "atomic" does not do is make any guarantees about thread safety. If thread A is calling the getter simultaneously with thread B and C calling the setter with different values, thread A may get any one of the three values returned -- the one prior to any setters being called or either of the values passed into the setters in B and C. Likewise, the object may end up with the value from B or C, no way to tell.

Ensuring data integrity -- one of the primary challenges of multi-threaded programming -- is achieved by other means.

Adding to this:

atomicity of a single property also cannot guarantee thread safety when multiple dependent properties are in play.

Consider:

 @property(atomic, copy) NSString *firstName;
 @property(atomic, copy) NSString *lastName;
 @property(readonly, atomic, copy) NSString *fullName;

In this case, thread A could be renaming the object by calling setFirstName: and then calling setLastName:. In the meantime, thread B may call fullName in between thread A's two calls and will receive the new first name coupled with the old last name.

To address this, you need a transactional model. I.e. some other kind of synchronization and/or exclusion that allows one to exclude access to fullName while the dependent properties are being updated.

This is explained in Apple's documentation, but below are some examples of what is actually happening.

Note that there is no "atomic" keyword, if you do not specify "nonatomic", then the property is atomic, but specifying "atomic" explicitly will result in an error.

If you do not specify "nonatomic", then the property is atomic, but you can still specify "atomic" explicitly in recent versions if you want to.

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

Now, the atomic variant is a bit more complicated:

//@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_;
    }
}

Basically, the atomic version has to take a lock in order to guarantee thread safety, and also is bumping the ref count on the object (and the autorelease count to balance it) so that the object is guaranteed to exist for the caller, otherwise there is a potential race condition if another thread is setting the value, causing the ref count to drop to 0.

There are actually a large number of different variants of how these things work depending on whether the properties are scalar values or objects, and how retain, copy, readonly, nonatomic, etc interact. In general the property synthesizers just know how to do the "right thing" for all combinations.

Atomic :

Atomic guarantees that access to the property will be performed in an atomic manner. E.g. it always return a fully initialised objects, any get/set of a property on one thread must complete before another can access it.

If you imagine the following function occurring on two threads at once you can see why the results would not be pretty.

-(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 : Return of fully initialised objects each time makes it best choice in case of multi-threading.

Cons : Performance hit, makes execution a little slower

Non-Atomic :

Unlike Atomic, it doesn't ensure fully initialised object return each time.

Pros : Extremely fast execution.

Cons : Chances of garbage value in case of multi-threading.

Easiest answer first: There's no difference between your second two examples. By default, property accessors are atomic.

Atomic accessors in a non garbage collected environment (i.e. when using retain/release/autorelease) will use a lock to ensure that another thread doesn't interfere with the correct setting/getting of the value.

See the "Performance and Threading" section of Apple's Objective-C 2.0 documentation for some more information and for other considerations when creating multi-threaded apps.

Atomicity atomic (default)

Atomic is the default: if you don’t type anything, your property is atomic. An atomic property is guaranteed that if you try to read from it, you will get back a valid value. It does not make any guarantees about what that value might be, but you will get back good data, not just junk memory. What this allows you to do is if you have multiple threads or multiple processes pointing at a single variable, one thread can read and another thread can write. If they hit at the same time, the reader thread is guaranteed to get one of the two values: either before the change or after the change. What atomic does not give you is any sort of guarantee about which of those values you might get. Atomic is really commonly confused with being thread-safe, and that is not correct. You need to guarantee your thread safety other ways. However, atomic will guarantee that if you try to read, you get back some kind of value.

nonatomic

On the flip side, non-atomic, as you can probably guess, just means, “don’t do that atomic stuff.” What you lose is that guarantee that you always get back something. If you try to read in the middle of a write, you could get back garbage data. But, on the other hand, you go a little bit faster. Because atomic properties have to do some magic to guarantee that you will get back a value, they are a bit slower. If it is a property that you are accessing a lot, you may want to drop down to nonatomic to make sure that you are not incurring that speed penalty. Access

courtesy https://academy.realm.io/posts/tmi-objective-c-property-attributes/

Atomicity property attributes (atomic and nonatomic) are not reflected in the corresponding Swift property declaration, but the atomicity guarantees of the Objective-C implementation still hold when the imported property is accessed from Swift.

So — if you define an atomic property in Objective-C it will remain atomic when used by Swift.

courtesy https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c

In a single line:

Atomic is thread safe. Nonatomic is thread-unsafe.

Atomic properties :- When a variable assigned with atomic property that means it has only one thread access and it will be thread safe and will be slow in performance perspective, will have default behaviour.

Non Atomic Properties :- When a variable assigned with nonatomic property that means it has multi thread access and it will not be thread safe and will be fast in performance perspective, will have default behaviour and when two different threads want to access variable at same time it will give unexpected results.

Related