In TMI, Michael Helmbrecht gives overly detailed answers to popular mobile development questions.
Ever browsed the web for help, only to find the popular answers leave you hungry for more? In this series, Realm’s very own Michael Helmbrecht takes a stab at giving a more detailed answer to some of the most popular mobile dev questions on the interwebs. For our first episode, Michael gets inspired by a question originally raised by Alex Wayne and decides to tackle the underlying topic of Objective-C property attributes:
weak, and so on.
I’m Michael Helmbrecht from Realm, and I am here to answer your questions on Stack Overflow about mobile development. Today we will start with iOS and focus on Objective-C, following the question What’s the difference between the atomic and nonatomic attributes?, raised by Alex Wayne. We will also cover the rest of the primary property attributes you might encounter.
Property Attributes in Objective-C
In Objective-C, when you declare a property, after you type
@property, there are sometimes words in parentheses (
retain). Here I’ll explain what those mean, and why you might use them in certain situations.
Get more development news like this
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 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.
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.
The second category of property attributes you can have are ones that modify access. There are also two in this class:
readwrite (with self-explanatory titles).
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.
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
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.
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.
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.
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 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.
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! 🐶