Question

I know that in Objective-c there's a very easy way to declare variables like this:

NSArray* myArray;

@property(retain) NSArray* myArray;

@synthesize myArray;

This way you can use self.myArray as both the setter and getter while retaining the variable. However this will also allow you to do one more thing, which is avoiding yourself using dealloc. As far as I understand, this two lines are the same:

self.myArray = nil;
[myArray release];

My question is, which one is the preferred way? Is there any cases where one of them will work and the other one won't?

EDIT: Sorry, I meant release, not dealloc...

Was it helpful?

Solution

Updates at bottom.

When working with (retain) synthesized properties, the best way to do your dealloc duties is to set the property to nil. The reason I say that this is the "best" way is that it ensures that all the contracts implied by the property declaration are met. For instance, if your property was declared atomic (which it will be, unless you specifically declare it nonatomic) the ONLY way to guarantee that the unsetting of this property on dealloc is done with the same atomic guarantees is to set it to nil using the property in dealloc. It also means that it will behave correctly with regard to any Key-Value Observations of your object - This can be important especially if you use Cocoa Bindings.

When doing your own memory management for a (perhaps private) instance variable without a corresponding property, there are several idioms. The simplest, but most dangerous, is to simply release the iVar, like so:

- (void)dealloc
{
    [myArray release];

    [super dealloc];
}

This will cause the retain on the iVar to be released, but as others mentioned, will leave the now-potentially-stale pointer around to potentially, if erroneously, be accessed by stale or non-retained pointers that may exist pointing to the object being dealloced. Next along the way is the idiom suggested by another answer:

- (void)dealloc
{
    [myArray release], myArray = nil;

    [super dealloc];
}

An even safer, if more pedantic, idiom for this is:

- (void)dealloc
{
    id temp = myArray;
    myArray = nil;
    [temp release];

    [super dealloc];
}

This further limits the chances for a stale read of the pointer by clearing the iVar BEFORE releasing the object pointed to. But, due to the potential for instruction reordering, even this is not a 100% guarantee against a stale read on all architectures.

Although there's much more to say on the topic of concurrency and memory management, in general, if you have a @synthesized property setter, you should just use it in dealloc. Doing so means that if you change the behavior of the @property the dealloc behavior will automatically be correct with respect to the @property declaration.

IMPORTANT NOTE: Using atomic properties != thread safety. (In fact, if you ask me atomic properties are a waste, but...) See here for more details.

UPDATE

This recently got upvoted again, and while I stand by what I said here about the atomic guarantees with synthesized retain properties, and some other content in the original answer is of value on its own, I feel the need to tell the other side of the story. Dave DeLong alluded to some of this in the comments, but I figured it'd be worth adding the detail to the main answer.

I maintain it's true that the only way to maintain the atomicity guarantees is to set the property to nil via the setter. BUT you shouldn't care, and here's why: If an object is being dealloced, that means (if your object graph is correct) that there should be no living references to that object. If there are no living references to the object, then it's not possible for anyone to be caring about the atomicity guarantees of the operation that clears the property.

I also mentioned KVO in the original answer as a reason to use the setter in dealloc, but Dave DeLong mentioned KVO in the comments as a counterpoint. He's right, and here's why: Again, if an object is being dealloced, all KVO observers should already have been removed from it (again, there should be no living references, KVO or not). Indeed, if this is not the case it won't be long until you'd see a console message telling you that your object went away with observations still in place.

In short, while you can't make atomicity guarantees equivalent to those of a synthesized setter in dealloc, it should never matter (and if it does, something else is broken.)

OTHER TIPS

You should never call dealloc yourself (except under very unorthodox circumstances).

Instead of dealloc, you should call [myArray release] and let the released process take care of this for you.

Have a look here for way more info than you'd probably like on a dealloc method as well.

Whenever you have any instance variable that is an object, you have to release it in the dealloc method. So in your case you have to use

- (void)dealloc
{
    [myArray release], myArray = nil;

    [super dealloc];
}

Setting to nil in theory should have the same effect as releasing the ivar. You should never call the dealloc method directly however. In the dealloc method you sometimes see the idiom mentioned by David, specifically:

[myArray release], myArray = nil;

The reason for this is to avoid a very unlikely race condition where someone might try accessing the released object before dealloc completes. By assigning the property to nil this allows the attempted access to fail gracefully.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top