1
votes

I'm building an iPhone application where I detach some threads to do long-running work in the background so as not to hang the UI. I understand that threads need NSAutoreleasePool instances for memory management. What I'm not sure about is if the threaded method calls another method - does that method also need an NSAutoreleasePool?

Example code:

- (void)primaryMethod {
    [self performSelectorInBackground:@selector(threadedMethod) withObject:nil];
}

- (void)threadedMethod {
    NSAutoreleasePool *aPool = [[NSAutoreleasePool alloc] init];

    // Some code here

    [self anotherMethod];

    // Maybe more code here

    [aPool drain];
}

- (void)anotherMethod {
    // More code here
}

The reason I ask is I'm receiving errors that objects are being autoreleased with no pool in place, and are "just leaking."

I've seen other questions where people didn't have autorelease pools in place at all, and I understand why an autorelease pool is needed. I'm specifically interested in finding out whether an autorelease pool created in (in this example) threadedMethod applies to objects created in anotherMethod.

3
Short answer is yes. See my response.SwiftArchitect

3 Answers

7
votes

To answer your question, yes, anotherMethod is using the NSAutoreleasePool you created in threadedMethod, and anything you autorelease there will be released when aPool is released/drained.

So it is unlikely that your error is stemming directly from this code (unless there is more going on).

Put a break point on _NSAutoreleaseNoPool (add it by name in the Breakpoints window) and run your code in the debugger and it will stop when autorelease is called without a pool and that should resolve your problem.

0
votes

In your example, yes, NSAutoreleasePool is carrying across methods since the invocation of [self anotherMethod] is nested inside -(void)threadedMethod.

  • Q: NSAutoreleasePool carrying across methods?
  • A: It depends:
    1. Across nested invocations, yes.
    2. Across sibling invocations, no.

And no matter what, the NSAutoreleasePool instance itself goes out of scope when the parent scope goes away. -in your example, at the very end of -(void)threadedMethod { }.

The article mentioned earlier (http://thegothicparty.com/dev/macos/nsautoreleasepool/) is quite clear about that.

-1
votes

The autorelease pool does carry through to anotherMethod. However, when your threaded function ends, you should call [aPool release] instead of [aPool drain]. They are roughly equivalent, but aPool release causes the NSAutoreleasePool to release itself in addition to all the other objects in the pool. When your threaded function ends after calling drain, the autorelease pool still has a retain count of +1! Odds are, the "just leaking" object is aPool!

EDIT:

Jim Puls is right about release and drain being equivalent. The Apple docs clearly say they are identical in the non-garbage collected environment, and drain is better in the garbage collected case. My fault for not reading the docs!

Here's an article that presents a general overview of NSAutoreleasePools - it should help point you in the right direction. Since there is a virtual stack of autorelease pools, the topmost one will be used everywhere within your app - regardless of where objects are being autoreleased.

http://thegothicparty.com/dev/macos/nsautoreleasepool/