views:

811

answers:

4

Here is the gist of some code I'm writing. I'm concerned that I am not properly addressing the retain/release issues with the array class method on NSMutableArray. Is the following actually leaking memory?

for(a while) { 
    // do stuff
    NSMutableArray *a = nil;
    // do stuff
    if (!a) {
        a = [NSMutableArray array];
    }
} // for(a while)
+6  A: 

From the Cocoa Memory Managment Rules:

You take ownership of an object if you create it using a method whose name begins with “alloc” or “new” or contains “copy” (for example, alloc, newObject, or mutableCopy), or if you send it a retain message. You are responsible for relinquishing ownership of objects you own using release or autorelease. Any other time you receive an object, you must not release it.

Therefore with the line:

a = [NSMutableArray array];

you do not take ownership of the array, and it will be passed to you autoreleased. The memory will be handled for you automatically by the autorelease pool, and once it is no longer being used, it will be released for you. If you want to keep the array outside the current event, however, you must retain it, otherwise it will be released for you.

Perspx
+2  A: 

Yes, if you want it to stick around.

The returned object is an autoreleased object which will get deallocated when its autorelease pool gets purged.

All the array class methods that begin with "array" return these types of autoreleased objects.

Read this doc by apple

Kaom Te
+7  A: 

You wouldn't leak memory in this code, and releasing the array yourself will cause a crash when the array is autoreleased at the end of the run loop.

Most Cocoa classes provide a couple of ways of making a new object, and are very consistent with this convention:

  1. [[NSSomeObject alloc] init] : you are responsible for releasing the object (instance method).

  2. [NSSomeObject someObject] : the object will be autoreleased for you, usually at the end of the run loop (class method). It's roughly equivalent to [[[NSSomeObject alloc] init] autorelease].

The proper use of the instance method would be:

a = [[NSMutableArray alloc] init];
// do stuff
[a release];

The proper use of the class method would be:

a = [NSMutableArray array];
// do stuff, array is in the autorelease pool

Note that Apple has recommended you stay away from the convenience methods as much as possible to improve performance. This is controversial advice, may not save much processor time, and separates the alloc-init from the release on an object you may not actually care much about keeping.

Ryan McCuaig
Excellent set of answers. Thanks so much.
dugla
Hi,I got to a conclusion from your answer. Please tell me am I right ?So, It is good to alloc and release memory than autorelease for iPhone programming. We should use less autorelease methods.Thank you.
srikanth rongali
Yes, you should limit your use of `autorelease`. It's convenient, but objects that are autoreleased will stay in the autorelease pool until the next time around on the run loop. Objects that are explicitly released will be deallocated more or less immediately.
Ryan McCuaig
It's definitely worth reading Brent Simmons's advice at http://inessential.com/2010/06/28/how_i_manage_memory. He makes a good point 3/4 in, in which he notes: "I've found that any drawbacks by use of autorelease are over-shadowed by other issues."
Ryan McCuaig
A: 

That's valid. It may help to just manage things manually when you have questions, to learn.

There is a convention:

  • init prefixes (init, initWithString:) indicate a retain count of 1, where
  • objectname prefixes (string, stringWithString:) indicates an autoreleased object

I have had the habit, for years, to release what I can at the call site, rather than pushing it to be autoreleased. Some autorelease issues then become painfully difficult to track down. Sure, autorelease is a convenience to the programmer in this case (provided nothing goes wrong), but adversely affects reuse, clarity, and performance (moreso in large codebases/programs).

Justin