When is an autoreleased object actually released?
Asked Answered
P

2

16

I am new in objective-c and I am trying to understand memory management to get it right.

After reading the excellent
Memory Management Programming Guide for Cocoa by apple my only concern is when actually an autoreleased object is released in an iphone/ipod application. My understanding is at the end of a run loop. But what defines a run loop in the application?

So I was wondering whether the following piece of code is right. Assume an object

@implementation Test

- (NSString *) functionA {
    NSString *stringA;
    stringA = [[[NSString alloc] initWithString:@"Hello"] autorelease]
    return stringA;
}

- (NSString *) functionB {
    NSString *stringB;
    stringB = [self functionA];
    return stringB;
}

- (NSString *) functionC {
    NSString *stringC;
    stringC = [self functionB];
    return stringC;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    NSString* p = [self functionC];
    NSLog(@"string is %@",p);
}

@end

Is this code valid?

From the apple text I understand that the NSString returned from functionA is valid in the scope of functionB. I am not sure whether it is valid in functionC and in viewDidLoad.

Thanks!

Phthisic answered 23/3, 2010 at 8:2 Comment(0)
H
18

Yes, your functions are valid, and return objects using correct Cocoa conventions for retain/release/autorelease/copy.

To answer your question about what the runloop is, in your application's main() function, it invokes UIApplicationMain(). You can imagine UIApplicationMain looks something like this:

void int UIApplicationMain (int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName) {
    UIApplication *app = /* create app using principalClassName */;
    [app setDelegate:/* create delegate using delegateClassName */];
    while (![app shouldTerminate]) {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        event = [app getNextEvent];
        [app dispatchEvent:event];
        [pool drain];
    }
}

That while loops is similar to what the UIKit is actually doing, and each trip through that while loop is like a trip through the runloop, where the function getNextEvent blocks waiting for some event to happen. All of your methods are typically called from within something like dispatchEvent:. You might try setting a break point in one of your methods, like an IBAction, and looking in the debugger call stack way up at the top to see the names of the UIKit methods that handle the events and runloop. Since each of your methods are called from within that while loop, each time you call autorelease on an object, that object is added to that outter pool in the run loop. When the current event is finished being dispatched, the pool is drained, and those objects are finally sent release messages.

One last note. There can be more than one autorelease pool, that aren't always at the end of the event loop. Sometimes you might allocate tens of thousands of objects in one trip thorough the event loop. When that happens, you might setup additional inner auto release pools in your own methods to keep the number of autoreleased objects in autorelease pools down. Auto release pools can stack.

Harmon answered 23/3, 2010 at 8:46 Comment(5)
Do I understand correctly that if I didn't create any autorelease pools all autoreleased variables will stay in memory till application is not closed?Bowrah
Kind of, the system frameworks create some autorelease pools for you at the top of the stack of the main thread in methods like UIApplicationMain(). However, if you started your own thread, and didn't create a pool, then yes those objects would leak. The autorelease method logs to the console in that case.Harmon
Ok, thanks, but this is strange, it is normal practice to use constructors which return autoreleased objects and don't release them, but it is actually the same as to have memory leak (memory is allocated till application is closed). Or I don't understand something?Bowrah
The autorelease pool created for you by functions like UIApplicationMain is drained once per trip through the event loop. So the objects will go away very frequently. If you make your own thread, and then create autoreleased objects on that thread, you'll need to periodically drain and reset your autorelease pool.Harmon
Ok, thanks Jon, now it makes sense, the only thing is I'm not really clear what event loop in this case is, can you give an example of event?Bowrah
C
0

There's nothing wrong with that code. It will compile and run as you expect.

The NSString object returned from functionA is still valid upon return since it's being passed down the stack to the next guy (functionB) who is now keeping track of it.

Champollion answered 23/3, 2010 at 8:5 Comment(1)
"Passed down the stack" is probably not the best choice of phrase because it implies a stack is used for return values, which isn't always the case.Womera

© 2022 - 2024 — McMap. All rights reserved.