Darren Findlay
Darren Findlay

Reputation: 2563

How to set up an autorelease pool when using [NSThread detachNewThreadSelector:toTarget:withObject:]

Hi I'm usuing [NSThread detachNewThreadSelector:toTarget:withObject:] and I'm getting a lot of memory leaks because I have no autorelease pool set up for the detached thread. I'm just wondering where I actualy do this? Is it before I call

[NSThread detachNewThreadSelector:toTarget:withObject:]

or in the method that is being ran in the other thread?

Any help would be appreciated, some sample code would be great.

Thanks.

Upvotes: 3

Views: 7780

Answers (5)

Adarsh V C
Adarsh V C

Reputation: 2314

Create the new thread:

[NSThread detachNewThreadSelector:@selector(myMethod) toTarget:self withObject:nil];

Create the method that is called by the new thread.


- (void)myMethod
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    // Your Code
    [pool release];
} 

What if you need to do something to the main thread from inside your new thread (for example, show a loading symbol)? Use performSelectorOnMainThread.

[self performSelectorOnMainThread:@selector(myMethod) withObject:nil waitUntilDone:false];

Refer :- iPhone SDK Examples

Upvotes: 5

Guillaume
Guillaume

Reputation: 21736

You have to set up an autorelease pool in the method you call and that will be executed in the new detached thread.

For example:

// Create a new thread, to execute the method myMethod
[NSThread detachNewThreadSelector:@selector(myMethod) toTarget:self withObject:nil];

and

- (void) myMethod {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    // Here, add your own code
    // ...

    [pool drain];
}

Note that we use drain and not release on the autoreleasepool. On iOS, it has no difference. On Mac OS X, if your app is garbage collected, it will triggers garbage collection. This allows you to write code that you can re-use more easily.

Upvotes: 6

visakh7
visakh7

Reputation: 26400

The documentation states that the method run in the thread must create and destroy its own autorelease pool. So if your code has

[NSThread detachNewThreadSelector:@selector(doThings) toTarget:self withObject:nil];

The method should be

- (void)doThings {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  //Do your things here
  [pool release];
}

Upvotes: 3

user23743
user23743

Reputation:

Do it in the method you call. Essentially, you should set up the method that gets called as a self-contained work unit (in fact, it will then be compatible with being called through either [NSOperation][1] or Grand Central Dispatch, too: both better ways of organising concurrent work).

But what if I can't change the implementation of the method I'm calling on a new thread?

In that case, you would go from doing this:

[NSThread detachNewThreadSelector: @selector(blah:) toTarget: obj withObject: arg]

to doing this:

[NSThread detachNewThreadSelector: @selector(invokeBlah:) toTarget: self withObject: dict]

- (void)invokeBlah: (id)dict {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  id obj = [dict objectForKey: @"target"];
  id arg = [dict objectForKey: @"argument"];
  [obj blah: arg];
  [pool release];
}

rather than using the dictionary, you could also create an NSInvocation that encapsulates the remote object call. I just chose a dictionary because it's the quickest way to show the situation in a SO answer. Either would work.

Upvotes: 3

Simon Lee
Simon Lee

Reputation: 22334

in the method you call with the thread... i.e. given this...

[NSThread detachNewThreadSelector:@selector(doStuff) toTarget:self withObject:nil];

Your method would be...

- (void)doStuff {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  //Do stuff
  [pool release];
}

Upvotes: 9

Related Questions