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.
Three things are being declared here: an anonymous enumerated type is declared, ShapeType
is being declared a typedef for that anonymous enumeration, and the three names kCircle
, kRectangle
, and kOblateSpheroid
are being declared as integral constants.
Let's break that down. In the simplest case, an enumeration can be declared as
enum tagname { ... };
This declares an enumeration with the tag tagname
. In C and Objective-C (but not C++), any references to this must be preceded with the enum
keyword. For example:
enum tagname x; // declare x of type 'enum tagname'
tagname x; // ERROR in C/Objective-C, OK in C++
In order to avoid having to use the enum
keyword everywhere, a typedef can be created:
enum tagname { ... };
typedef enum tagname tagname; // declare 'tagname' as a typedef for 'enum tagname'
This can be simplified into one line:
typedef enum tagname { ... } tagname; // declare both 'enum tagname' and 'tagname'
And finally, if we don't need to be able to use enum tagname
with the enum
keyword, we can make the enum
anonymous and only declare it with the typedef name:
typedef enum { ... } tagname;
Now, in this case, we're declaring ShapeType
to be a typedef'ed name of an anonymous enumeration. ShapeType
is really just an integral type, and should only be used to declare variables which hold one of the values listed in the declaration (that is, one of kCircle
, kRectangle
, and kOblateSpheroid
). You can assign a ShapeType
variable another value by casting, though, so you have to be careful when reading enum values.
Finally, kCircle
, kRectangle
, and kOblateSpheroid
are declared as integral constants in the global namespace. Since no specific values were specified, they get assigned to consecutive integers starting with 0, so kCircle
is 0, kRectangle
is 1, and kOblateSpheroid
is 2.
Best Answer
As mentioned, in Swift most of the time you can achieve what you need with the
?
optional unwrapper operator. This allows you to call a method on an object if and only if the object exists (notnil
) and the method is implemented.In the case where you still need
respondsToSelector:
, it is still there as part of theNSObject
protocol.If you are calling
respondsToSelector:
on an Obj-C type in Swift, then it works the same as you would expect. If you are using it on your own Swift class, you will need to ensure your class derives fromNSObject
.Here's an example of a Swift class that you can check if it responds to a selector:
It is important that you do not leave out the parameter names. In this example,
Selector("sleep::")
is not the same asSelector("sleep:minutes:")
.