Property Attributes in Objective-C
In Objective-C, when you declare a property, after you type @property
, there are sometimes words in parentheses (strong
or weak
; copy
or retain
). Here I’ll explain what those mean, and why you might use them in certain situations.
There are many property attributes in Objective-C. If you are working with Objective-C code, you might see that when you declare a property in you interface file, you type @property
and then sometimes there are parentheses with one or more keywords. These can be really confusing both for beginners and more advanced developers who see words that are scarcely used. What we are going to talk about today is the words that can go in the parentheses, what they mean and what they do, and when you might want to use some of them. These property attributes fall into three categories for different ways in which they change the way that your property works. The first ones are atomic
and non-atomic
.
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
The second category of property attributes you can have are ones that modify access. There are also two in this class: readonly
and readwrite
(with self-explanatory titles).
readonly
readonly
makes it so this property is read-only. There is no setter for it at all. One caveat is that it cannot be readonly
to everyone else, but readwrite
to me: if you say readonly
, it is read-only to everybody, including you.
readwrite
(default)
On the flip side, there is readwrite
, which, of course, allows both read and write. That is the default; again, if you do not write anything, you have a readwrite
property.
What if you want one property that works as readwrite
to you, but readonly
to everybody else? In your interface file you would declare it as readonly
, but in your implementation file, you would create a class extension and redefine it as readwrite
. The keyword in the interface communicates to others that they cannot write to (a.k.a., change) the property. However, the class extension at the top of your implementation (.m) file will redefine the property with the same name, only as readwrite
instead, allowing you to write to the property within the implementation file.
Storage
The third category of property attributes is one that affects the way that your property stores its value. All properties are backed by instance variables, and in old-school Objective-C, you had to do all that yourself. You had to create the instance variable, and make sure they stayed in sync through getter and setter methods. Apple eventually introduced the @synthesize
directive which would generate all that stuff for you, but they have since made that automatic for every variable. Now you just declare a property and it magically has a getter, a setter, and a backing variable that actually manages the value. However, if you want to tweak the way that that relationship works, there are four options for storage modifiers.
strong
(default)
The default is called strong
. Strong just means you have a reference to an object and you will keep that object alive. As long as you hold that reference to the object in that property, that object will not be deallocated and released back into memory.
weak
Strong’s analog is weak
. Weak gives you a reference so you can still “talk” to that object, but you are not keeping it alive. If everyone else’s strong references go away, then that object is released. The nice thing about weak references is that they will automatically nil references that go away. If you have a reference to an object and all of the strong
references to it go away and it gets deallocated, your weak reference does not point to some junk memory, which can give you crashes. It will just automatically nil itself out. Then, in Objective-C, you can safely send messages to nil
and nothing happens. (You may want to handle that, of course, in some other way.) weak
references are really common in delegate patterns (delegation essentially requires a weak reference to the delegate object).
The two storage attributes that you may not be quite as used to seeing are called assign
and copy
.
assign
assign
is the keyword used for primitives. It is pretty easy to understand: If you do not have an object, you cannot use strong
, because strong tells the compiler how to work with pointers. But if you have a primitive (i.e. int, float, bool, or something without the little asterisk after the type), then you use assign
, and that makes it work with primitives.
copy
Lastly, there’s a keyword called copy
. Copy I have seen most commonly with strings. It works really well with all kinds of mutable objects. If you set a copy
property, instead of just setting both references to the same object, what it actually does is it makes a copy of the object you are setting and then sets the property to that copy. If I write in a string, it just copies that string so there are now two copies of that string. It leaves mine with me at the variable I passed in and just saves the copy. That way I can keep going with my string and I can modify it, and the one that I set remains the way that it was when I set it.
I hope that this help from me (and Frank) will help you out on all your future Objective-C projects and figuring out property attributes. Good luck, and catch the next episode soon! 🐶
网友评论