Slick's Definitive Guide To Properties

I keep answering similar questions with similar answers, so I'm trying to put this stuff in one place. I'll just start referring people to this thread. Please feel free to offer comments or suggestions, and I'll make corrections where appropriate. I'm open to debate on anything mentioned here, but this is what I do, it works well for me, and is drawn from the advice of significantly more-experienced coders.

Thread Guide

You can just scroll down and start reading, but the core of this thread involves these three posts:

Right off the bat, it is extremely important to keep in mind that properties and instance variables are not the same thing. It's relatively common for books and examples to use the same name - and that's ok - but you have to remember that they are two separate entities. One is a variable, the other is a method or pair of methods - myProperty and setMyProperty.

What @property (and @synthesize) does for you is create the getter/setter methods. You are still able to make your own if you want. In the 'old' days before Obj-C 2.0, you had to make them yourself. There are several ways of doing getters/setters, and that's why there are several options when you declare your @property. A typical getter/setter pair using retain might look like this:

You don't need to create these methods (unless you have a reason to customize them). These are what are created behind-the-scenes when you @synthesize a @property. I'm just illustrating them so that you can see what they do.

The important part here is what's going on in the setter. The new value is retained, the old value is released, and then the new value is assigned to the instance variable. This is what you want to happen, to avoid leaks.

After that, simply remember that these are methods just like any other method. If you want to use a method within your class, you send a message to 'self'. You can't just do:

calculateThisBigHairyNumber;

You have to do:

[self calculateThisBigHairyNumber];

Getters/setters, whether done manually or via @property, are exactly the same. If you want to use them - and you pretty much always do - then you have to use self.

Now, the value. Creating an instance variable and defining the @property does NOT populate the instance variable with anything. It is empty until you put something in it. It is a little like a typed placeholder; yes, you've indicated that this instance variable will be an NSArray, thus only NSArrays will be allowed to occupy this space, but you haven't actually created an NSArray yet. So somewhere in your program, you will want to do that. Exactly where depends on when you'll need it, but for sake of discussion let's use viewDidLoad.

Now we need to get that new object assigned to the instance variable. HOWEVER, you want to use the accessor methods as much as possible. A very good guideline is to use instance variables directly ONLY in dealloc, and/or in any custom getter/setter methods. Everywhere else, use the accessors.

Now we need to clean up our memory. According to Apple's Memory Management Rules, you need to release any object where you have done any of the following method: alloc, new, copy, retain. We did an alloc, therefore we are responsible for releasing this object. So at last we reach:

Now, why did we do this in 3 lines? Why didn't we just go straight to the instance variable, like this:

Figure 9

ivInstanceVariable = [[MyClass alloc] init];

Look closely at the example setter back there and notice what it does. It performs 2 actions: it releases the old value, and retains the new value. By using direct assignment to the instance variable, we did not use the setter method. This means the old value was NOT released. However, our instance variable is now pointing to our new object, so we no longer have a way of talking to the old object, and thus no means to send it the release message. Therefore, the old value has been leaked.

Now you might be thinking "hey, this is viewDidLoad, this is one of the first things that happens... there probably isn't an old value to leak in the first place." That's probably true, but you want to be consistent with your techniques. And viewDidLoad can be run multiple times. You don't want to have to be constantly thinking "Ok, I'm in viewDidLoad, so I'll use the instance variable, but now I'm viewWillAppear so I'll use the property... uh, what should I do in my table view delegate methods?"

The old value isn't the only problem here; what about the new object that was just created? Ah HA!, you're thinking... that gets released in dealloc! And if you do nothing else with the instance variable, that is possibly also true. But what happens if you do this in some other method:

Figure 10

ivInstanceVariable = someOtherObject;

Now your 'new' object has become the 'old' object, and is subject to the same leak we just just described. Dealloc will only do any good - well, first of all you have to make sure to release your instance variable there, or else it REALLY won't do any good - on the object that exists in your instance variable at the time that dealloc is called. If you've swapped out objects in the instance variable 10 times, then there are 10 leaked objects, and only the last one will be released in dealloc.

Technically, you can do the same thing that the setter is doing yourself. So that would be along these lines:

...but this is just begging for trouble. You have to be incredibly consistent with how you use this instance variable. If you slide in an extra release somewhere, now you've overreleased the object, and that's bad. If you forget to do this release, now you've leaked the object, and that's bad. You may think you are saving yourself some effort by using the instance variable directly, but in reality you are causing yourself a bigger headache.

Can you avoid this hassle by using autorelease, like this:

Figure 12

ivInstanceVariable = [[[MyClass alloc] init] autorelease];

No. Autorelease means exactly that: the object will be sent a release message later. By using direct assignment, the property was not used, so the object does not receive the extra retain. The release message will balance the alloc here, so the object will be deallocated. Whenever that happens, and it may not be instantly, your instance variable will be referencing a dead object. You'll crash sooner or later.

The life of your objects can be described in these 3 phases:
1. Create it
2. Do something with it
3. Get rid of it, ASAP

So let's return to the 3-line pattern from above and see how that links up:

One more pattern to discuss is the combination of alloc/init with the setter method. I see this a lot:

Figure 14

[self setMyProperty: [[MyClass alloc] init]];

This is great, right? It's one line of code, I'm using the setter method... perfect.

Wrong. This is a leak. Every time. Let's take it in steps. First, we create an object:

[[MyClass alloc] init]

This newly-created object has a retain count of 1, though for purposes of this discussion I'm going to use relative retain counts, not absolute. So doing alloc/init results in a +1 retain count.

Next, we assign this object directly using the setter method. Remember what the setter method does: it releases the old value (we don't care right now), and it retains the new value. That's another +1. We are now at a total of +2.

And there's no Step 3... We didn't assign the new object to a local variable first, so there is nothing to release.

Eventually, our parent class will be deallocated. In the dealloc method, we release the instance variable:

[myInstanceVariable release];

Release changes the retain count by -1.

This is worth emphasizing: Sending the 'release' message does NOT (necessarily) kill the object. You could create an object, send it the 'retain' message 50 times, and then send it the 'release' message 50 times. It will continue to exist (+1 from alloc) until its retain count is 0. When you send the 51st 'release' message, the one that brings the retain count to 0, THAT will kill the object. But the object is killed because the retain count is now 0, not simply because the release message was sent. That's a subtle but important distinction.

Uh oh. Our MyClass object never got down to 0, so it still exists. We no longer have any means to talk to it, so that object has been leaked.

The same would be true if a new value gets assigned to the property. Remember, the setter will release (-1) the old value, and the object we created is now the old value. So again we are left with a +1 net retain count, again we do not have any means to communicate with the object, and again it is a leak. And as a double-bonus, if the new object is another alloc/init creation, we're replacing a leaked object with another leaked object.

In order to be diligent, you can send a release message (before it's gone, obviously) this way:

[[self myProperty] release];

...but if you get here, you are largely defeating the purpose of using @properties in the first place. The whole point is to simplify memory management. Manually releasing properties this way is just confusing the issue. Better to use the 3-line pattern and just worry about this stuff up front and be done with it.

If you are dead-set against using the 3-line pattern, you can accomplish this with a single line:

Figure 15

[self setMyProperty: [[[MyClass alloc] init] autorelease]];

This does not leak. It's mostly a style choice at this point.

One other aspect that is worth pointing out is the use of other object's properties. Up to this point, we've only been worrying about the properties declared in our own class. But the rules all still apply to any other object's properties, or to any other class (such as collections) that performs some kind of memory management action. Arrays and dictionaries jump to mind. Each of these is a leak (without deliberate additional action on your part):

Collection classes will retain objects as they are added, and release them as they are removed. So the +1 -1 stuff described above still applies. The difference with pure properties is that collections still have the object, so in a worst-case scenario you can still get ahold of a reference and do any necessary releasing. But IMO, that's sloppy coding and is just begging for trouble.

Build your app. Heck, run your app. If you have no warnings, if it continues to function exactly as it did before, then you are not using your properties. If you do not understand why this is the case, then start over at the beginning of this thread and keep rereading until you do.

I suddenly got the idea for a tip that will help identify when instance variables are being used: custom colors.

So, head into Xcode's preferences:

Find the "Project Instance Variables" line and set the color to be something really obnoxious. I'm going with red here (and I changed the "Strings" line to something else, since it defaulted to red for me), but choose whatever will stand out amongst your other colors.

Even though synthesizing properties will create getters/setters for you, you can customize them if you want. So if you have created custom getters/setters, use the instance variables there as well. Here I have a customized getter that makes sure my instance variable is populated with an array:

Close. Using dot-syntax does not inherently cause leaks like that, so that isn't the issue. Mis-using dot-syntax, which IMO is very easy to do, leads to issues.

So these are equivalent:

self.title = ...
[self setTitle: ...]

As are these:

imageView.image = ....
[imageView setImage:...]

In the second case, the only possible concern there would be using the instance variable directly, which you want to avoid. If that's a local variable, it's fine as-is. If it is an instance variable, then you want to use the accessor methods, so it should become:

That's some really great info! Very clear and not greek for once! :rolleyes:
I really appreciate that! NICE! B-)
One Question...
I've been having a problem with a view...when I leave the view to go to the next view, then come back to it all the info is there BUT I want it to be cleared! Is there some type of release or reload that I should be using on the view I want cleared out?

That's not really a release issue. You need to define how you want the view to look when it is displayed, and choose an appropriate place to do so. viewDidLoad will fire one time, so is not useful for constantly changing stuff. viewWillAppear/DidAppear, and/or viewWillDisappear/DidDisappear may be more appropriate, as they fire each time a view is displayed or goes away.

One question. I see alot of examples with self.iboutletvariable = nil; in the ViewDidUnload method. I get that this gets called to release any subviews in a viewController that is currently not in view when mem is low.
I see it also being done for other non-iboutlet variables as well, e.g. self.array = nil;.

My confusion here is, with properties. Using dot syntax as a setter method like:
self.variable = nil. Would this in effect release an old variable whilst retaining a new variable with value = nil? If, so - is it really freeing up memory seeing that it still has a retain count of 1?

My confusion here is, with properties. Using dot syntax as a setter method like:
self.variable = nil. Would this in effect release an old variable whilst retaining a new variable with value = nil? If, so - is it really freeing up memory seeing that it still has a retain count of 1?

Well, let's take a basic case with an integer, and a local variable.

int myInt = 5;

We've declared a variable, defined its type, and given it a value. If the value is changed...

myInt = 10;

...there isn't anything keeping track of the old value (5). It is one variable, just with a new value.

Same idea with objects.

id myObject = [anArray objectAtIndex:2];

If we then change that:

myObject = [anArray objectAtIndex:5];

...myObject no longer knows about the old value. If we change it again:

myObject = nil;

...myObject again no longer knows about the old value, but this time does not refer to any particular object. That's the point of nil. It's sort of a universal "nothing". The current value of this variable is nothing.

A characteristic of Objective-C is that you can send a message to nil... and nothing happens. It's like a black hole. You can send all the messages that you want, but they aren't going anywhere. This would be a crash in some languages, Obj-C just decides 'eh, whatever' and doesn't do anything.

So bringing this back around to @properties. Although you don't see this code when you @synthesize the @properties, the setter method that a retain property creates looks something like this:

This is how accessors were created before @properties were introduced with Obj-C 2.0. What this does is:
1. release the old value
2. retain the new value
3. assign the new value to the instance variable.

So your question is what happens when you send in nil. Same thing:
1. the old value is released.
2. the new value is retained.
---> Wait, what? Ok, keep in mind what I just said. The new value is nil. Nil is like a black hole. Retain is simply another message. So, sending the retain message to nil doesn't do anything.
3. the new value (nil) is assigned to the instance variable.
---> So the instance variable is now nil.

If we were looking at values instead of variables, it would look more like this:

Carry that through to the next time you send in an actual object. So right now, the value is nil, but we're sending in a new array.
1. the old value is released.
---> Nil. Black hole. Message.
2. the new value (array) is retained
3. the new value is assigned to the instance variable.

I still don't get it what I did wrong. As I understand it, setting the values to nil shouldn't change the retainCount. And without setting them to nil, their retainCount should be 0 because i released them.

That's +1 overall. At some point, the view will release the image view (-1), and you will release your property in dealloc (-1), at which point you should crash.

You also should not be doing a manual release of properties like that - that is only done in dealloc. If you wish to clear out a property, do this:

[self setMyProperty: nil];

Aside from that, an image view and an image aren't really any different than any other object. If you did an alloc, copy, new, or retain, you should release. imageNamed does not use any of those, so don't release. If you used a different UIImage initializer, like alloc/initWithContentsOfFile, then you would release.

Hi Brian, could you please write down a little code snippet on how to "make" a Label or Button that doesn't leak? I tried to write an example app to check whether my code will free a viewcontroller completely when i leave it. But I must have missed something in your guide, cf. my other thread:

Nice writeup Brian, but there's one more important check needed to avoid a common bug if you want to write your own setters (or modify an instance variable in general). Before releasing the old value, you'll need to make sure the new value isn't the same. Otherwise you may be trying to retain a freed object and crash.

There's some additional locking code @synthesize adds if you don't declare your properties to be nonatomic, so for most purposes it's easiest just to stick with the synthesized accessors to keep your code simpler.

Yes, that is a perfectly valid example of a safe setter too. It's always good practice to retain the new value before releasing the old in an assignment, whether that occurs in a setter or elsewhere in your code.

Sorry, I didn't mean to sidetrack the threadI just wanted to point out a common memory management mistake that may not be immediately obvious. That's what I meant by common, not necessarily how often the failure occurs. I've been bitten by it before; particularly if you're collaborating with others you want your code to be bulletproof. Without a guard in place, your code may not crash immediately, leading to some elusive debugging if it happens to crash in a distant part of your program. (Hint: use NSZombieEnabled to catch prematurely deallocated objects.)

Sorry, I didn't mean to sidetrack the threadI just wanted to point out a common memory management mistake that may not be immediately obvious. That's what I meant by common, not necessarily how often the failure occurs.

I can see this happening - for example if you do self.property = [myArray objectAtIndex:chosenIndex] or something similar, you might wind up replacing an object with itself in the property. It's another good reason to @synthesize the setters; writing a good setter is harder than it looks.

I'm having a tough time envisioning how putting the same object into a setter again would be even a semi-common occurrence. Sounds like sloppy coding to me.

Well, the bugs that are really uncommon are often the most dangerous; they're harder to test for, and developers are less likely to know to look for them and know how to deal with them. I've actually seen this exact bug bite a coworker (he didn't implement the setter, but was using it for his current project), and it took him a couple of hours to track it down and fix it. That's a huge amount of company time wasted over something as trivial as passing a value into a setter method.

This thread offers excellent advice, and so I apologize for sidetracking it a little further, but I think this is worth emphasizing for anyone who is thinking about implementing properties or other built-in functionality manually: the way that property methods behave is an established convention that developers learn and rely on. One aspect of this convention is that setters should have no effect when the current value of the property is passed in (and it certainly shouldn't destroy the object ). For situations where this is a possibility, like the one Smasher mentioned, I'd argue that relying on the convention actually makes the client code less sloppy -- all of the bookkeeping related to memory management, including making sure an object is not accidentally destroyed, has been completely encapsulated by the property. This frees the calling code from being cluttered with error checking, which would only distract from what the code is actually supposed to do (as well as provide one more place for bugs to creep in).

To summarize and get this back on topic: Brian's done an excellent job describing how properties work and how they should be used. If you ever decide to implement property methods manually, make sure they adhere to the established conventions, so that developers who do follow Brian's good advice don't get burned by your code.