Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

tod

Cancelled
Original poster
Oct 3, 2009
162
100
I have a quick memory management question. Here is the code:

Code:
NSArray *keys = [[[NSArray alloc] initWithObjects: @"1", @"2",nil] autorelease];	
	
NSMutableArray * temp = [[NSMutableArray alloc] init];
	
temp = [NSMutableArray arrayWithArray:keys];
	
[temp release];

When I release the temp object, the app crashes. If I remove that line, it runs, but of course it will leak memory.

I've been looking through the documentation for hours and I've looked at countless examples and I can't figure out why this crashes. I alloc an object, do something with it, then release it. Everything I've written conforms to the documentation, as far as I understand it. What am I missing here?
 
What are you "doing" with it other than reassigning it right away, which actually throws out what you just alloc'd? That is what is causing the leak.
 
Code:
NSMutableArray * temp = [[NSMutableArray alloc] init];
Temp has a retain count of 1 at this point.

Code:
temp = [NSMutableArray arrayWithArray:keys];
Now temp has been assigned to a new autoreleased object. Meaning, the object gets created with a retain count of 1, but will be released at a future later point which means you should not release it.

Code:
[temp release];
By calling release here, you set the retain count to 0, which causes temp to deallocate.

The crash you see comes from the future point in time when the autorelease pool empties. It contains a reference to temp which is no longer a valid object (pointer), which causes the crash.

I would suggest reviewing:
- C pointers
- Cocoa memory management, specifically the section on autorelease pools
 
Now temp has been assigned to a new autoreleased object. Meaning, the object gets created with a retain count of 1, but will be released at a future later point which means you should not release it.

Thank you. This is very helpful. For anyone reading this in the future, here is what I was thinking:

I understood that in following code

Code:
temp = [NSMutableArray arrayWithArray:keys];

[NSMutableArray arrayWithArray:keys] is an autoreleased object that I don't have to worry about. I thought that I was assigning that autoreleased object to temp (which I had ownership of, and thus could dispose of later). So in my mind, it was like this: set [my object with a retain count of 1] to be equal to [this convenient, autoreleased object];

Much of the discussion I found centered around retain and release counts, which I had no problem with as long as I didn't use convenience methods. I had no idea that temp would become autoreleased in that case.
 
[NSMutableArray arrayWithArray:keys] is an autoreleased object that I don't have to worry about. I thought that I was assigning that autoreleased object to temp (which I had ownership of, and thus could dispose of later). So in my mind, it was like this: set [my object with a retain count of 1] to be equal to [this convenient, autoreleased object];

Much of the discussion I found centered around retain and release counts, which I had no problem with as long as I didn't use convenience methods. I had no idea that temp would become autoreleased in that case.

As kainjow pointed out, it's important the understand the distinction between the pointer (temp) and the object it is pointing to. When you do this:

Code:
NSMutableArray * temp = [[NSMutableArray alloc] init];

You are basically saying, "give me a new block of memory with an NSMutableArray in it" and "make temp point to this memory." The NSMutableArray that you just created will have a retain count of 1. The "retain count" of temp is entirely dependent on the object it is pointing to.

Then when you do this:

Code:
temp = [NSMutableArray arrayWithArray:keys];

You are now saying, "give me an autoreleased NSMutableArray in a new block of memory" and "switch temp so that it points to this new memory." The key thing here is at this point you have now created two distinct NSMutableArrays, each living in their own blocks of memory with their own distinct retain counts. Temp only knows about the retain count of the object it is currently pointing to, so when you reassign temp to the autoreleased array, you are losing any reference to the first array and its retain count, which is a memory leak. If you want to assume ownership of an autoreleased object, you need to do this:

Code:
NSMutableArray *temp;
temp = [NSMutableArray arrayWithArray:keys];
[temp retain];

<do some stuff with temp>

[temp release];

I put the declaration of temp on its own line just to be clear that there was no prior assignment to it in the code. Of course if this code was all happening in one method, there probably would be no need to retain temp.
 
I have a quick memory management question. Here is the code:

Code:
NSArray *keys = [[[NSArray alloc] initWithObjects: @"1", @"2",nil] autorelease];	
	
NSMutableArray * temp = [[NSMutableArray alloc] init];
	
temp = [NSMutableArray arrayWithArray:keys];
	
[temp release];

When I release the temp object, the app crashes. If I remove that line, it runs, but of course it will leak memory.

That release isn't leaking memory, so you can remove it.

However, your second assignment to the variable "temp" is leaking memory, so you should release it's previous contents before the (re)assignment.

My rule of thumb is to never manually assign anything to an object pointer directly unless it is nil, or, within clear view above in the source code above, either uninitialized or assigned to an autoreleased object. Else do something to make it nil without leaking first (which is what property setters do for you automatically, but not when doing a manual direct assignment).
 
Sorry to redirect the discussion slightly, but I have a followup question for the gurus here.

If the NSArray * keys is autoreleased, is that object still being retained when assigned to the new NSMutableArray temp? In other words, are the elements within the NSArray being retained or will this new temp object contain elements flagged for autorelease?
 
Sorry to redirect the discussion slightly, but I have a followup question for the gurus here.

If the NSArray * keys is autoreleased, is that object still being retained when assigned to the new NSMutableArray temp? In other words, are the elements within the NSArray being retained or will this new temp object contain elements flagged for autorelease?

There are two different things that you are talking about that could potentially be autoreleased. One is the collection of objects in the keys array, and the other is the keys array itself. Calling NSMutableArray arrayWithArray: creates a new, autoreleased array containing the objects in the given array. So if the keys object was autoreleased, it could and would just get freed eventually. On the other hand, the objects in the keys array that also get put in the temp array will be retained by the temp array (increasing their retain count to 2 at that point) so they will persist even when keys is (auto)released and the objects get released by keys.

Or to put it another way, calling autorelease on an array technically won't autorelease the objects it contains. Those objects will still be retained by the array until the array is released by the autorelease pool and dealloc'ed, at which point the objects it contains will be released.
 
Thanks admanimal. I suspected it was a deep retain (I don't know the actual nomenclature so I am borrowing the deep copy term).

I think the correct term is "strong reference." This would be in contrast to a weak reference where you just have a pointer to something but do not retain it.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.