views:

72

answers:

1

I'm looking at some open source code and trying to understand why the author has done something in a particular way.

The class is a wrapper around NSArray to create a stack data structure with push, pop, etc.

One method is topObject which returns the topmost object on the stack and its implementation is:

- (id)top {
    return [[[stack lastObject] retain] autorelease]; // stack is an instance of NSMutableArray
}

What's with the retain followed by an immediate autorelease?

My initial reaction was that this would prevent an analyser warning about a memory leak, but I analysed without the retain/autorelease and there was still no warning.

Looking at the lifecycle, an object would be created, pushed to the stack and released, so the stack owns the object (the underlying array will retain it upon adding).

So I don't understand the use of the retain/autorelease here...

+7  A: 

Let's assume top would look like this:

- (id) top {
    return [stack lastObject];
}

Then imagine this:

foo = [bar top];
[bar removeAllObjects];
// Do something with foo

The following would happen: The second line would make the retain count drop to 0, and by the third line foo would point to deallocated memory. But with the retain and autorelease the retain count is 1, until the pool is emptied thus on the third line foo would still point to a valid object.

DarkDust
Makes sense, thanks.
Jasarien
It's still not correct doing that imho. The Memory Management Programming Guide states "Just as you shouldn’t be concerned with an object’s actual retain count, you shouldn’t be concerned about whether an object returned to you is autoreleased or not. The only concern is, do you own it or not." - so the retain+autorelease should occur in the foo = [bar top]; line, not in the -(id) top{} method.
w.m
Well explained answer.
Meta-Knight
@w.m. That was my thinking too. It's also how I would have done it, and probably why I had trouble understanding why it was done this way.
Jasarien
@w.m: You are correct with this, but it's about the point of view of the caller. But here, we as a callee are trying to ensure that the caller indeed does get the behavior he is expecting, even if he does something later on that will make us release the object.
DarkDust
w.m, the same document says: “ Cocoa’s ownership policy specifies that received objects should typically remain valid throughout the scope of the calling method. It should also be possible to return a received object from the current scope without fear of it being released.” If an action invalidates the return value of an earlier action, interface abstraction is lost. Foundation collections are explicitly specified as a policy exception.
Ahruman