Andrey Chernukha
Andrey Chernukha

Reputation: 21808

Memory management while copying objects

I know that my question has already been discussed on StackOverflow but i found the answer not complete for my needs. So the question is:

NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
secondArray = [firstArray mutableCopy];

what is retain count for the secondArray now? 2 or 1? Should i release it twice or just once? Does copy or mutableCopy increases retain count of the COPYING (secondArray in this event) object?

Upvotes: 1

Views: 702

Answers (2)

futureelite7
futureelite7

Reputation: 11502

NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
secondArray = [firstArray mutableCopy];

What is happening is that you've created a memory leak. You just lost the reference assigned to secondArray when you overwrote it with the mutableCopy of firstArray with this line.

secondArray = [firstArray mutableCopy];

If you then release secondArray twice, the program will crash because you're then overreleasing the mutable array assigned by

secondArray = [firstArray mutableCopy];

What you need to do is to make sure you're not overwriting retained references by mistake, and balance retains with releases.

Upvotes: 1

DarkDust
DarkDust

Reputation: 92335

You should never care about the absolute retain count. Only that you're "balanced", that means for every alloc, new*, copy, mutableCopy and retain you need a corresponding release or autorelease (when not using ARC, that is).

If you apply this rule to each line you can see that your second line has an alloc, but there's no release. In fact, it's absolutely useless to allocate an instance here since you're not interested in it anyway. So it should simply read:

NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [firstArray mutableCopy];
// There is no third line.

But let's discuss your original code and see what happened:

NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects: obj1,obj2,nil];
NSMutableArray *secondArray = [[NSMutableArray alloc] init];
// secondArray points to a new instance of type NSMutableArray
secondArray = [firstArray mutableCopy];
// You have copied another array (created a new NSMutableArray
// instance) and have overwritten the pointer to the old array.
// This means that the instance allocated in line 2 is still there
// (was not released) but you don't have a pointer to it any more.
// The array from line 2 has been leaked.

In Objective-C, we often speak of ownership: there are very few methods that make you the "owner" of an object. These are:

  • alloc
  • new*, as in newFoo
  • copy and mutableCopy
  • retain

If you call these, you get an object for which you are responsible. And that means you need to call a corresponding number of release and/or autorelease on these objects. For example, you're fine if you do [[obj retain] retain]; and then [[obj autorelease] release];

Upvotes: 5

Related Questions