adit
adit

Reputation: 33644

What happens if you try to release an object that has been released?

What if I have an object, say NSIndexPath in which before I do a copy I always release it first?

Is it possible to have a memory count under 0? I am doing this to prevent memory leaks.. is this a good way?

//global already has some value before in here or it doesn't have a value.. I want to update
//this with a new value (I no longer care to the old pointer)

 [global release]
 global = [indexPath copy];

Upvotes: 1

Views: 840

Answers (2)

André Morujão
André Morujão

Reputation: 7133

Don't. When the retain count reaches 0, your object will be dealloc'ed and its pointer will become invalid, so using it again will cause unpredictable results (namely crashing).

You should read through Apple's Memory Management Guide.

This is the fundamental rule:

  • You only release or autorelease objects you own. You take ownership of an object if you create it using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message.
  • You use release or autorelease to relinquish ownership of an object. autorelease just means “send a release message in the future” (specifically: when the used autorelease pool receives a drain message).

Update:

As Josh pointed out, the one case you need to consider is when global and indexPath are the same. In that case, you would still "need" the pointer (to perform the copy), so you either autorelease (instead of releasing) or you use a temporary variable to handle that.

Upvotes: 8

jscs
jscs

Reputation: 64002

What you are doing is essentially correct, so long as global either has an old value that you no longer need or is nil. If it is one of a class's ivars, it will be nil when an instance of the class is created. The one catch is that if the new indexPath happens to be the same object as the one that's already in global, you will have over-released and you will crash.

// global points to object at 0x8BADFOOD
// indexPath also happens to be 0x8BADFOOD; for some reason, it
// hasn't changed since last time. This _can_ happen.
[global release];    // object at 0x8BADFOOD is deallocated
global = [indexPath copy];    // indexPath no longer valid! 
                              // Crash! Bang! Boom!

The way to avoid this is to use a temp variable.

When you declare a property as copy and synthesize that property, the setter method that is created looks essentially like this, and you can do the same thing:

- (void)setMyFloozit:(Floozit *)newFloozit {
    // Copy first in case newFloozit and myFloozit are for
    // some reason the same object
    // Take ownership of a copy of newFloozit
    Floozit * tmp = [newFloozit copy];
    // We no longer need old value of myFloozit, so we release it.
    [myFloozit release]; 
    // tmp contains a value that we own, we just need to assign
    // it to the correct name.
    myFloozit = tmp;
}

This could be made slightly better by checking first to see whether newFloozit and myFloozit are the same, and doing nothing if they are.

Upvotes: 0

Related Questions