2012-03-16 4 views
0

Я недавно отлаживал проблему с зомби с операциями и выяснил, что вызов cancelAllOperations в очереди не отменяет эту операцию, и на самом деле очередь операций была пуста, хотя операция все еще бежал.NSOperation работает, но отсутствует в NSOperationQueue

Структура была viewcontroller, которая асинхронно загружала набор изображений из Интернета и выполняла некоторые изменения на них. Соответствующие (анонимные) их фрагменты следуют:

@implementation MyViewController 

- (id) init 
{ 
    (...) 
    mOperationQueue = [[NSOperationQueue alloc] init]; 
    (...) 
} 

- (void) viewDidAppear:(BOOL)animated 
{ 
    (...) 
    MyNSOperation * operation = [[MyNSOperation alloc] initWithDelegate:self andData:data]; 
    [mOperationQueue addOperation:operation]; 
    [operation release]; 
    (...) 
} 

- (void) dealloc 
{ 
    (...) 
    [mOperationQueue cancelAllOperations]; 
    [mOperationQueue release]; 
    (...) 
} 

- (void) imagesLoaded:(NSArray *)images 
{ 
    (...) 
} 

И данная операция:

@implementation MyNSOperation 

- (id) initWithDelegate:(id)delegate andData:(NSDictionary *)data 
{ 
    self = [super init]; 
    if (self) 
    { 
     mDelegate = delegate; // weak reference 
     mData = [data retain]; 
     (...) 
    } 
    return self; 
} 

- (void) main 
{ 
    NSAutoReleasePool * pool = [[NSAutoReleasePool alloc] init]; 

    mImages = [[NSMutableArray alloc] init]; 
    // load and compose images 
    mAlteredImages = (...) 

    [self performSelectorOnMainThread:@selector(operationCompleted) withObject:nil waitUntilDone:YES]; 

    [pool release]; 
} 

- (void)operationCompleted 
{ 
    if (![self isCancelled]) 
    { 
     [mDelegate imagesLoaded:mAlteredImages]; 
    } 
} 

Наблюдаемый поток следующим образом:

  • ViewController показан, призывающие инициализации и viewDidAppear запуска операция.
    • [операции mOperationQueue] содержит ровно один элемент;
  • Вскоре после того, операция переходит в основной и
  • ViewController происходит выход пользователя до завершения операции.
  • dealloc называется на ViewController (поскольку операция сохраняет слабую ссылку)
    • [mOperationQueue операций] содержит ноль (!) Элементы
  • cancelAllOperations отправляется в очередь операции
    • [ NSOperation cancel] не вызывается, в результате появляется видимое фиктивное состояние приложения.
  • dealloc заканчивает
  • операция завершается
    • isCancelled возвращает ложь, в результате зомби вызова

Документация NSOperationQueue однако четко указано, что «операции не остаются в очереди, пока они закончить свою задачу ». который выглядит как нарушение контракта.

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

Заранее спасибо.

+0

@Combuster ... вы можете поделиться своим рабочим кодом для своего вопроса здесь – Priya

ответ

0

cancelAllOperations не отменяет уже начатую операцию. Он только информирует об этом факте и позволяет операции отменить себя, всякий раз, когда он хочет. Таким образом, вы можете получить условие повышения. Продолжайте с deallocacion, после вы уверены, что операция отменена.

+0

Тогда, как * он * уведомляет операцию - [self isCancelled] продемонстрировал, что этого недостаточно. – Combuster

+0

Поскольку вы должны следить за отменой операции, вы можете отправить там свое уведомление. Ср http://developer.apple.com/library/mac/documentation/Cocoa/Reference/NSOperation_class/Reference/Reference.html#//apple_ref/doc/uid/TP40004591-RH2-SW5 – Matthias

+0

Чтобы уточнить: isCancelled следует использовать * по * операции, чтобы определить, была ли она отменена, поэтому операция может реагировать. Метод * не * предназначен для предоставления информации об успешном удалении наружу. – Matthias