как правильно использовать autoreleasepool для nsoperationqueue - PullRequest
2 голосов
/ 29 декабря 2010

У меня есть приложение, которое я реорганизую, и я только что реализовал многопоточность, чтобы пользовательский интерфейс мог работать более плавно.В симуляторе iphone я не получаю никаких утечек, но при тестировании на моем iPhone 3G, работающем на iOS 4.2, я вижу утечку памяти.Я много занимался поиском правильного способа реализации автозапуска с помощью очереди операций, помощь будет принята с благодарностью.

Я создал запрос nsoperationqueue в моем viewcontroller как таковой

- (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];
}

Ответы [ 2 ]

2 голосов
/ 29 декабря 2010

Во-первых, вы не должны просто создавать, а затем освобождать очередь.Более естественно создать эту очередь в качестве одного из иваров вашего класса, а затем освободить ее, когда ваш контроллер представления исчезнет (вы также можете отменить любые ожидающие операции и отменить / дождаться завершения любых выполняющихся операций).

Во-вторых, вам не нужен пул автоматического выпуска в методе, который создает операцию и добавляет ее в очередь, поскольку этот метод вызывается из основного потока.Вместо этого вам нужен пул автоматического выпуска из метода, который фактически вызывает ваш объект (это то, что может выполняться в другом потоке).

Итак, у вас может быть следующее (при условии, что вы назовете свою очередь ива-очередь _):1005 *

- (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];
}

Вы также можете инициализировать свою очередь по требованию, поэтому вместо инициализации в viewDidLoad проверьте ее наличие и при необходимости инициализируйте везде, где бы вы ни добавили операцию.Это может быть включено в собственный вызов метода, но ленивая инициализация здесь, вероятно, на самом деле не нужна, поскольку очереди довольно легкие.

0 голосов
/ 29 декабря 2010

Вы должны создать NSAutoreleasePool в начале метода, который NSOperation будет вызывать (в данном случае, firstRun), и опустошить его в конце метода.

...