views:

269

answers:

5

This is on the iPhone.

So what if I have a function like

- (SomeObject*)buildObject;

Do I need to pass in a variable that I have already alloc'd outside like

- (void)assignObject(SomeObject** out);

Or can I do

- (SomeObject*)buildObject
{
   return [[[SomeObject alloc] init] autorelease];
}

and use it like

SomeObject* obj = [[otherObject buildObject] retain];

I would like to do the last one, but as far as I've read this is undefined because autorelease only guarantees the object until the end of the function?

A: 

You are safe using the last one. I use this style in every one of my apps and have never had issues. Autorelease will last for many, many, many execution cycles, much longer than the end of the function.

coneybeare
+4  A: 

In Objective-C, the memory management contract goes as follows: whoever calls alloc is responsible for calling release. If the constructing function calls [[[Class alloc] init] release] then the object is quickly created and destroyed.

To get around this, the constructing function would need to use autorelease as follows:

return [[[Class alloc] init] autorelease];

That registers the object to be released at the end of the current run loop unless something retains it, such as the caller of the constructing function. In your case, the second example is exactly what you want to do.

So:

- (SomeClass*) buildObject {
   return [[[SomeClass alloc] init] autorelease];
}

- (void) doSomething {
   c = [self buildObject];
   // Call [c retain] if you want c to stay around after the current run
   // loop is finished and clean it up later, e.g. in your delloc method.
}
Bryan Kyle
So I don't have to call retain immediately if I don't want to use it outside of doSomething?
DevDevDev
Yes you do. The object (if it's an autoreleased one) is guaranteed to stay in memory until the end of the current method, but not longer. It **might** live longer, but you can't depend on that.
Pascal
(Assuming that you don't have your own autorelease pool in place, of course)
Pascal
So you are disagreeing with Bryan SanHolo? If doSomething does some lengthy computation c is not guaranteed to be there by the end of the function?
DevDevDev
No, Bryan is correct, and I'm not disagreeing with him. ;) **c** is guaranteed to be around for the whole *doSomething* method, but when that method ends, the pool might be cleaned and **c** goes away. If you call another method **from within *doSomething***, then **c** will still be around since *doSomething* has not yet ended.
Pascal
(I misread your initial question, sorry, overlooked the second *don't*. Answer to your initial question is *No, you don't have to retain* :) )
Pascal
+1  A: 

Autorelease guarantees the object until the release/drain of the current NSAutoreleasePool.

It's perfectly acceptable (and standard practice) to return an autoreleased object from a method.

Wevah
Was my answer inaccurate?
Wevah
+4  A: 

There is kind of a settlement on how you should do this in Cocoa; read the docs for details.

Basically, if you have a method that starts with init, new or copy, you return an object that is retained and you must release it.
If you provide a convenience method, you return an object that is autoreleased.

This means:

- (id) initMyObject
{
    self = [super init];
    if (self) {
        // do something
    }
    return self
}

➔ You must release objects obtained with this method

- (MyObject *) myObject
{
    return [[[MyObject alloc] initMyObject] autorelease];
}

➔ This is a convenience method - the object is autoreleased by the method and you must retain it if you want to keep it longer than until the autorelease pool empties (which you should assume happens at the end of the current method).

Pascal
Additionally, one of the neat things about the Clang Static Analyzer is that it will warn you if you are not properly following the naming conventions for methods when retaining or autoreleasing objects as return values. It's a great sanity check.
Brad Larson
+1  A: 

You can do what you want to do. Autorelease doesn't issue a release message to the object until the current autorelease pool is freed. That happens either because you explicitly requested it (by allocing+initing an NSAutoreleasePool and later draining it), or because the system did so. The system autorelease pool creation and draining happens at the beginning and end of event cycles; from the memory management programming guide:

The Application Kit automatically creates a pool at the beginning of an event cycle (or event-loop iteration), such as a mouse down event, and releases it at the end, so your code normally does not have to worry about them.

In practice, that means that what you want to do is safe, as all the code you write will get executed together within a single event cycle.

Josh Bleecher Snyder
" Autorelease guarantees that the object is around until the current autorelease pool is freed"No, it doesn't. Autorelease is nothing but a delayed message mechanism. It guarantees nothing.
NSResponder
Good point -- I misspoke. Autorelease maintains its reference count handle to the object until the current autorelease pool is freed.
Josh Bleecher Snyder