Search code examples
objective-ccocoamemory-managementretaincount

Another "Retain, then Release" question


being a Cocoa/Obj-C newbie I am going through the "Cocoa Programming for Mac OS X" book by Aaron Hillegass and - leaving apart the fact that now we have also the chance to use GC to avoid all this reasoning - I am not sure I get the reason for some of those retains.

In particular in one of the examples Aaron gives as good programming practice:

- (void) setFoo:(NSCalendarDate *)x
{
    [x retain];
    [foo release];
    foo = x;
}

I don't get the reason for retaining the x instance at the first line of the method:

[x retain];

The scope of this instance is just the set method, right? When exiting the method scope the x instance should be deallocated anyway no? Besides, when assigning x to foo with:

foo = x;

foo will be anyway pointing to x memory cells and will therefore increment the pointed object retain count, no? This should ensure the memory won't be deallocated.

So, what's the point? I am sure I am missing something, of course, but don't know what exactly.

Thanks, Fabrizio


Solution

  • Retain means: I will be needing this object to stay around, it must not be deallocated. If x wouldn't be retained, the following is likely to happen:

    You assign x to foo, so foo now points to the address where your NSCalendarDate is. Someone releases or autoreleases this object, it's retain count eventually drops to 0 and the object is deallocated. Now your foo still points to that address, but there's no longer a valid object. Sometime later, a new object is created and by chance it's situated at the same address than your old NSCalendarDate object. Now your foo points to an entirely different object !

    To prevent that, you need to retain it. You need to say, please do not deallocate the object yet, I need it. Once you're done with it, you release it which means I no longer need the object, you can clean it up now if nobody else needs it.

    Now for the classical three part assignment. Consider your setFoo: would look like this:

    - (void) setFoo:(NSCalendarDate *)x
    {
        [foo release];
        [x retain];
        foo = x;
    }
    

    This is a very bad idea. Consider your object is the only one who has retained the NSCalendarDate object, and consider you would then do: [self setFoo:foo];. Might sound silly, but something like this can happen. The flow would now be this:

    1. foo would be released. Its retain count might now drop to 0 and the object will get deallocated.
    2. Whoops, we're trying to retain and access a deallocated object.

    This is why you always first retain the new object, then release the old object.

    If you're coming from a Java or .NET background, it is very important to understand that a variable of type Foo * only contains the address of your object, nothing more. In Java or .NET, a variable that points to an object automatically "retains" it, if you will. Not so in Objective-C (in non-GC environments). You could consider a variable of type Foo * to be a weak reference, and you explicitly need to tell Objective-C whether you will still need that object at that address or not.