Methods That Call Methods: Basics of Autorelease?
Asked Answered
M

2

1

Just when I thought I've understood this topic completely, I'm back to basics.

I have a method that instantiates an autoreleased object, using (for example) stringWithFormat:

return [NSString stringWithFormat:@"what"];

Then I call this method from another method, and another method, each time returning this autoreleased NSString and in each level of the hierarchy. The code works fine and the NSString instance is intact at each level of the hierarchy.

I thought that since the instance is autoreleased, it could suddenly end up with a retainCount of 0 at any point in the call stack (i.e., one of the methods would be working on a released object). Is it true that I cannot depend on this object?

Edit: I realize the question wasn't too clear. Sorry. I mean:

Method1 ---calls--->    Method2 ---calls---> Method3 ---instantiates the string---> 
Magnitogorsk answered 28/9, 2010 at 20:43 Comment(2)
You'll likely never see a retain count of 0. If an object has a retain count of 1 when release is called, it gets deallocated instead of decrementing the retain count. Also, in the example, stringWithFormat might be clever enough to return the literal passed in since it has no format specifiers in it.Cheesecake
@JeremyP, good point about the retain counts never reaching zero. On the other point, my original example was actually return @"what";, which is the same in this example, I think.Magnitogorsk
M
1

It is safe to assume that an autoreleased object will not be deallocated in a stack frame below the frame in which it was allocated. So, in a call stack like

method1
  method2 <== instance allocated/autoreleased here
   method3 <== safe to use here

it is safe to assume an instance alloc/autoreleased in method2 is valid in method3 unless you play nasty tricks and drain a pool created in method1 from method3. This is because an autorelease pool in a higher frame cannot be drained (unless by stupidness) in a lower frame. Of course, once control returns to method1, all bets are off.

Autorelease pools alloc'd in a lower frame will not contain the instance autoreleased in method2 because they could not have been the active pool (they weren't created yet!) at the time of the autorelease.

Finally, unless a method lower in the call chain, between the method of interest and the method that instantiates and autoreleases an object instance creates and drains an autorelease pool, you are assured that the enclosing pool will not be drained until the end of the run loop.

Moeller answered 28/9, 2010 at 21:10 Comment(0)
D
4

The answer is that the NSAutoreleasePool is drained after all method calls and you are back in the run loop. That means that in a call stack the object will not be released as long as you do not return to the run loop.

Dramatist answered 28/9, 2010 at 20:55 Comment(7)
Is that a guarantee if I don't drain the autorelease pool, or it just happens to be what's happening?Magnitogorsk
That is a a fundamental guarantee. Autorelease pools do not automagically drain themselves. If they did, the very notion of autoreleased object would be entirely broken and unusable.Perichondrium
It's a guarantee. You should be safe to use the object for the remainder of the run loop.Workman
Thanks @bbum, @Robot K, and @GorillaPatch. This really helps. So if A calls B calls C calls D and D instantiates an autoreleased object, it's safe to use it all the way up to A, right? Just confirming before I mark this as accepted answer.Magnitogorsk
Yup -- totally safe. What is not implied by autorelease is any kind of thread safety.Perichondrium
Totally correct. You usually go with one autoreleasepool per thread. But it can be usefull to use more than one if you are allocating a lot of autoreleased objects in a tight loop. This could lead to a memory spike which would cause your problem getting killed if running on an iOS device. It is nice to remember that you are dealing with a stack of autoreleasePools. Calling autorelease on an object adds it to the topmost pool in the stack.Dramatist
Okay, thanks everybody for the help @Perichondrium @Robert K and @DramatistMagnitogorsk
M
1

It is safe to assume that an autoreleased object will not be deallocated in a stack frame below the frame in which it was allocated. So, in a call stack like

method1
  method2 <== instance allocated/autoreleased here
   method3 <== safe to use here

it is safe to assume an instance alloc/autoreleased in method2 is valid in method3 unless you play nasty tricks and drain a pool created in method1 from method3. This is because an autorelease pool in a higher frame cannot be drained (unless by stupidness) in a lower frame. Of course, once control returns to method1, all bets are off.

Autorelease pools alloc'd in a lower frame will not contain the instance autoreleased in method2 because they could not have been the active pool (they weren't created yet!) at the time of the autorelease.

Finally, unless a method lower in the call chain, between the method of interest and the method that instantiates and autoreleases an object instance creates and drains an autorelease pool, you are assured that the enclosing pool will not be drained until the end of the run loop.

Moeller answered 28/9, 2010 at 21:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.