I’ve written a small program to test whether NSInvocationOperation
would create an autorelease pool for the operation:
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
@end
@implementation MyClass
- (void)performSomeTask:(id)data
{
NSString *s = [[[NSString alloc] initWithFormat:@"hey %@", data]
autorelease];
if ([[NSThread currentThread] isMainThread])
NSLog(@"performSomeTask on the main thread!");
else
NSLog(@"performSomeTask NOT on the main thread!");
NSLog(@"-- %@", s);
}
@end
int main(int argc, char *argv[]) {
MyClass *c = [MyClass new];
if (argc == 2 && strcmp(argv[1], "nop") == 0)
[c performSomeTask:@"ho"];
else {
NSInvocationOperation *op = [[NSInvocationOperation alloc]
initWithTarget:c
selector:@selector(performSomeTask:)
object:@"howdy"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:op];
[op waitUntilFinished];
[op release];
[queue release];
}
[c release];
return 0;
}
It works as follows: if "nop" is passed on the command-line, it will execute -performSomeTask:
directly, on the main thread, with no autorelease pool in place. The resulting output is:
$ ./c nop
*** __NSAutoreleaseNoPool(): Object 0x10010cca0 of class NSCFString autoreleased with no pool in place - just leaking
performSomeTask on the main thread!
-- hey ho
The autoreleased string in -performSomeTask:
causes a leak.
Running the program without passing "nop" will execute -performSomeTask:
via an NSInvocationOperation
on a different thread. The resulting output is:
$ ./c
*** __NSAutoreleaseNoPool(): Object 0x100105ec0 of class NSInvocation autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x100111300 of class NSCFSet autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x100111b60 of class NSCFSet autoreleased with no pool in place - just leaking
*** __NSAutoreleaseNoPool(): Object 0x100105660 of class NSCFSet autoreleased with no pool in place - just leaking
performSomeTask NOT on the main thread!
-- hey howdy
As we can see, there are instances of NSInvocation
and NSSet
that are leaking but the autoreleased string in -performSomeTask:
isn’t leaking, hence an autorelease pool was created for that invocation operation.
I think it’s safe to assume that NSInvocationOperation
(and probally all NSOperation
subclasses in Apple’s frameworks) create their own autorelease pools, just like the Concurrency Programming Guide suggests for custom NSOperation
subclasses.