views:

119

answers:

3

I have this code in one of my classes:

- (void) processArray
{

   NSMutableArray* array = [self getArray];
   . . .
   [array release];
   array  = nil;
}


- (NSMutableArray*) getArray
{
   //NO 1:
   NSMutableArray* array = [[NSMutableArray alloc]init];

   //NO 2:
   NSMutableArray* array = [NSMutableArray array];
   . . .
   return array;
}

NO 1: I create an array and return it. In the processArray method I release it.

NO 2: I get an array by simply calling array. As I'm not owner of this, I don't need to release it in the processArray method.

Which is the best alternative, NO 1 or NO 2? Or is there a better solution for this?

+7  A: 

The method should return an autoreleased array, NO 2 is the better choice. The reason for this is that when you call the method with

   NSMutableArray* array = [self getArray];

you will expect as a matter of convention to not have to release the array. If you want to take ownership of it, you retain it, but otherwise you shouldn't have to care about it. In Cocoa, you only take ownership by explicitly sending alloc or retain or copy (or new). Since the processArray method doesn't do that, it shouldn't have to take care of releasing the array.

So you should use NO 2, and also you should remove these two lines:

[array release];
array  = nil;
Felixyz
+1 that convention really helps keep memory leaks and calls on nil in control.
Anurag
+1 In addition to that one should use the Clang Static Analyzer (already built into Xcode for Snow Leopard). This will help with memory management when using Build > Build and Analyze. An example:http://img682.imageshack.us/img682/2549/clanganalyzerinxcodeisa.png
bddckr
Felixyz, If I want the ownership of those arrays (which are being created in the "getArray"), then how can I achieve that? Do you have any example?
prathumca
@prathumca: NSMutableArray* array = [[self getArray]retain]; The object returned from `getArray` (following method NO 2) is autoreleased and will be deallocated on the next runloop, but if you retain it immediately when you get it, you will have ownership over it and it will keep alive until you `release` it. This is one of the primary purposes of `autorelease`: to be able to return objects and let the caller decide if they want to retain them.
Felixyz
+1  A: 

If the array and its contents use a lot of memory or its used lots of times, you'll want to release them straight away, so use option 1. According to the Objective-C guidelines, you'll want to prefix the word "new" to your subroutine name instead of "get" in that case.

If on the other hand, you want to reduce the number of lines of code that say simply [array release]; or similar then use option 2.

It is simply a balance between reducing lines of code, and reducing unnecessary temporary memory use.

Whilst the autorelease pool will help in reducing memory leaks and make your code smaller, sometimes you need to explicitly release everything as it goes out of use to keep the use of memory down.

HTH

EDIT

Ah - I stand corrected. Reading the iPhone version of the Memory Management Programming Guide for Cocoa I see that the iPhone guidelines are to use a prefix of "new..." so for example "newArray" in this case, if the caller is supposed to manually release and NOT a prefix of "create...". "Creating" can refer either to creation of manually released or of automatically released objects and so would be ambiguous. Text corrected above.

martinr
I think more than the number of lines of code, it's about strictly adhering to the convention of ownership. Memory related errors will make it virtually impossible to program in Objective-C otherwise.
Anurag
@martinr: What you're saying about the "create" prefix is interesting and makes sense, although it seems not to be used in the Cocoa classes. (There are many examples of CoreFoundation functions with "Create" in the name". I looked up the relevant documentation but couldn't find any mention of "create" methods: http://developer.apple.com/mac/library/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingMethods.htmlCould you point to the documentation you mentioned?
Felixyz
@martinr (after EDIT): ok that convention is good to know about. I could only find two examples of it in use in the actual iPhone API (newReferenceObjectForManagedObject: and newCacheNodeForManagedObject:), both on NSAtomicStore, and I suppose this has something to do with the "factory" character of that class (but haven't used it so I'm not sure if this is true).
Felixyz
A: 
- (void) processArray
{

   NSMutableArray* array = [[self getArray] retain];
   //Now you are the owner of array, so you take care to release it

   . . .

   [array release];
   array  = nil;
}


- (NSMutableArray*) getArray
{
   //create a new array 
   //temporarily the method owns the array
   NSMutableArray* array = [[NSMutableArray alloc]init];

   //fill in here with elements or what you want
   ..........

   [array autorelease];
   //autorelease here says "I don't own the result
   //if anyone cares about it, he should retain it himself

   return array;
}

So in short when you create new objects you should autorelease them before returning. Because if the calling method wants to use the result, the calling method should take care of retaining and releasing the result.

It's always good to run the Klang static analyzer for this issues, when you are not really sure in your retaining/releasing code : http://clang-analyzer.llvm.org/

Ican Zilb