views:

285

answers:

4

In Objective-C, if array1 is copied onto array2 using mutableCopy, and suppose the code is done in main(), who is responsible for releasing the objects contained in the array? Is it main() or array2?

A: 

It wouldn't make sense for a mutable array to be tied to an immutable array. main() would be responsible for releasing array1.

In my experience however, releasing objects only causes applications to crash. ObjC is fairly good at automatically managing memory. My Cocoa apps don't seem to ever need more memory than they started with, even after running several hours.

mcandre
Releasing objects is probably causing crashes because you haven't properly retained the object. Suggesting that someone ignore the rules of memory management is always a bad idea. Failing to release objects only works without leaking under garbage collection, and it's always bad practice.
Quinn Taylor
Also, neither array1 or array2 are responsible for releasing each other, but the mutable array is "tied" to the immutable array in that they both contain the same objects, at least to begin with.
Quinn Taylor
The garbage collection system is complicated. It tries to do some work for you while providing direct control. The result of this mixed method is that some objects autorelease and some need to be manually released. But in my experience, even the ones that are not autoreleased DO crash the programs if they are forcibly released.I suggest anyone ignore the rules of anything that causes program crashes when followed. As I said, my ObjC applications ignore garbage collection and they do not show any memory leaks after running for several hours. Practice over principle.
mcandre
It's actually not that complicated. You're misunderstanding the Obj-C memory management system — garbage collection is completely different from retain/release/autorelease. True, you do have to understand when an object needs to be retained or released, but there are only a few cases to remember. Odds are the reasons you're not seeing leaks are (1) most Cocoa methods return autoreleased objects, and (2) you may not be leaking enough objects to really notice. I can almost guarantee that if you ignore the memory management rules, you will have leaks. Try running in Instruments to find them. :-)
Quinn Taylor
+1  A: 

I reference this guide for Memory Management in Obj-C. He has a section on Arrays and Dictionaries, here's an excerpt:

Arrays, dictionaries etc. generally retain any objects added to them. (When dealing with 3rd party collection type objects, always check the documentation to see if they retain or not). This means that these collections will take ownership of the object, and you do not need to retain before adding.

The comments for the posting are also useful

ThaDon
+13  A: 

I think the previous answers have missed the point, or else the asker was pretty unclear. The actual question isn't talking about either array, but rather the array contents:

who is responsible for releasing the objects contained in the array? Is it main() or array2?

Both array1 and array2 are responsible for releasing the objects.

From the NSArray documentation:

"Arrays maintain strong references to their contents—in a managed memory environment, each object receives a retain message before its id is added to the array and a release message when it is removed from the array or when the array is deallocated."

To begin with, each of the objects are retained by the NSArray array1. When you create array2 via -mutableCopy, you get an NSMutableArray which points to the same objects, and retains each of them again. If you were to release array1 at this point, when its dealloc method were called it would release each of the objects it contains. However, array2 has retained them, so the objects won't be destroyed — only when their retain count reaches 0, which would happen if array2 were destroyed and nobody else has retained any of the objects (or when they are removed from array2).

Since collection classes (arrays, sets, dictionaries, etc.) handle retaining and releasing their contents, all you have to worry about is retaining or releasing the collection itself. Since you used -mutableCopy, remember that you have implicitly retained array2, so you should release it when you're done with it.

Quinn Taylor
Cheers, missed that.
Perspx
Thanks, I didn't know copy was shallow. :)
huggie
Ha! Didn't know it would suffice to have said that. It can be tough to gauge the level of detail required in a response. :-)
Quinn Taylor
+1  A: 

The ownership responsibilities are not changed by storing objects in an array. Here's an example:

int main(int argc, char *argv[])
{
    // ...

    NSObject *obj1 = [[NSObject alloc] init]; // owned
    NSObject *obj2 = [[NSObject alloc] init]; // owned
    NSObject *obj3 = [[[NSObject alloc] init] autorelease]; // not owned

    NSMutableArray *array1 = [NSMutableArray arrayWithObjects: obj1, obj2, obj3, nil]; // not owned
    NSMutableArray *array2 = [array1 mutableCopy]; // owned

    // ...

    [array2 release];
    [obj2 release];
    [obj1 release];

    // ...
}

This code directly allocates obj1 and obj2, so it owns them and must release them, but it autoreleases obj3, so it doesn't have to release that. In the same way, it doesn't own the result of arrayWithObjects:, so it doesn't release that, but it does own the result of mutableCopy, so it must release that. The objects being stored in an array is irrelevant—all you need to care about is ownership.

Both arrays keep strong references to their content, so obj1, obj2, and obj3 won't be deallocated as long as the arrays exist—but that's a detail of the NSArray contract, it doesn't affect how you manage the ownership of the objects or the arrays.

These are all details of Cocoa's memory management conventions, not arrays.

John Calsbeek
Thanks for taking the time to explain. :)
huggie