how to properly use autoreleasepool for an nsoperationqueue

I have an app that I am refactoring and I just implemented multithreading so that the UI may run smoother. In the iphone simulator I don't get any leaks but testing on my iPhone 3G running on iOS 4.2 I get a memory leak. I have done a lot of searching for the correct way to implement an autoreleasepool with an operationqueue, help will be greatly appreciated.

I have created an nsoperationqueue in my viewcontroller as such

- (void)loadData
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  NSOperationQueue *queue = [NSOperationQueue new];  // creates multithread for loading data without slowing UI
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];

  [queue addOperation:operation];
  [operation release];
  [queue release];
  [pool release];
}

Answers


First, you shouldn't just create and then release the queue. It's more natural to create that queue as one of your class's ivars and then release it when your view controller goes away (you can also cancel up any pending operations and cancel/wait for any running operations to complete).

Second, you don't need the autorelease pool in the method that creates the operation and adds it in the queue since that method is being called from the main thread. Instead, you need the autorelease pool from the method your object actually calls (this is what may be running on another thread).

So, you might have the following (assuming you name your queue ivar queue_):

- (void)viewDidLoad
{
  [super viewDidLoad];

  if( !queue_ ) queue_ = [[NSOperationQueue alloc] init];
  // other view loading code
}

- (void)loadData
{
  NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(firstRun) object:nil];
  [queue_ addOperation:operation];
  [operation release];
}

- (void)firstRun
{
  // Here we may run on another thread, so 1) we need an autorelease pool; and
  // 2) we need to make sure we don't do anything that requires a runloop
  NSAutoreleasePool* threadPool = [NSAutoreleasePool new];

  // do long-running things

  [threadPool drain];
}

- (void)dealloc
{
  if( queue_ ) {
    [queue_ setSuspended:YES];
    [queue_ cancelAllOperations];
    // you need to decide if you need to handle running operations
    // reasonably, but don't wait here because that may block the
    // main thread
    [queue_ release];
  }
  // other dealloc stuff
  [super dealloc];
}

You could also initialize your queue on demand, so instead of initializing in viewDidLoad, check for its existence and initialize if necessary anywhere you'd add an operation. This might be wrapped in a method call of its own, but lazy initialization here probably isn't really necessary as queues are pretty light-weight.


You should create an NSAutoreleasePool at the start of the method that the NSOperation will invoke (in this case, firstRun), and drain it at the end of the method.


Need Your Help

django-piston add value foreign key

django django-models foreign-keys django-piston

I'm trying to insert from REST API Django-piston a new value on my database.

Visual Studio 2008: Start custom build target via project/solution context menu - without add-in

c# visual-studio-2008 msbuild

I have a custom build target in a visual studio 2008 c# project. Is there a simple way to add a context menu item to the project, so that the custom build target can be executed via the ide? The bu...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.