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.
Best Answer
Since the question I asked has been seen many times I will provide a detailed answer of it. Feel free to modify it if you want to add more correct content.
First a recap on the question: frame, bounds and center and theirs relationships.
Frame A view's
frame
(CGRect
) is the position of its rectangle in thesuperview
's coordinate system. By default it starts at the top left.Bounds A view's
bounds
(CGRect
) expresses a view rectangle in its own coordinate system.Center A
center
is aCGPoint
expressed in terms of thesuperview
's coordinate system and it determines the position of the exact center point of the view.Taken from UIView + position these are the relationships (they don't work in code since they are informal equations) among the previous properties:
frame.origin = center - (bounds.size / 2.0)
center = frame.origin + (bounds.size / 2.0)
frame.size = bounds.size
NOTE: These relationships do not apply if views are rotated. For further info, I will suggest you take a look at the following image taken from The Kitchen Drawer based on Stanford CS193p course. Credits goes to @Rhubarb.
Using the
frame
allows you to reposition and/or resize a view within itssuperview
. Usually can be used from asuperview
, for example, when you create a specific subview. For example:When you need the coordinates to drawing inside a
view
you usually refer tobounds
. A typical example could be to draw within aview
a subview as an inset of the first. Drawing the subview requires to know thebounds
of the superview. For example:Different behaviours happen when you change the
bounds
of a view. For example, if you change thebounds
size
, theframe
changes (and vice versa). The change happens around thecenter
of the view. Use the code below and see what happens:Furthermore, if you change
bounds
origin
you change theorigin
of its internal coordinate system. By default theorigin
is at(0.0, 0.0)
(top left corner). For example, if you change theorigin
forview1
you can see (comment the previous code if you want) that now the top left corner forview2
touches theview1
one. The motivation is quite simple. You say toview1
that its top left corner now is at the position(20.0, 20.0)
but sinceview2
'sframe
origin
starts from(20.0, 20.0)
, they will coincide.The
origin
represents theview
's position within itssuperview
but describes the position of thebounds
center.Finally,
bounds
andorigin
are not related concepts. Both allow to derive theframe
of a view (See previous equations).View1's case study
Here is what happens when using the following snippet.
The relative image.
This instead what happens if I change
[self view]
bounds like the following.The relative image.
Here you say to
[self view]
that its top left corner now is at the position (30.0, 20.0) but sinceview1
's frame origin starts from (30.0, 20.0), they will coincide.Additional references (to update with other references if you want)
About
clipsToBounds
(source Apple doc)In other words, if a view's
frame
is(0, 0, 100, 100)
and its subview is(90, 90, 30, 30)
, you will see only a part of that subview. The latter won't exceed the bounds of the parent view.masksToBounds
is equivalent toclipsToBounds
. Instead to aUIView
, this property is applied to aCALayer
. Under the hood,clipsToBounds
callsmasksToBounds
. For further references take a look to How is the relation between UIView's clipsToBounds and CALayer's masksToBounds?.