Недавно я отлаживал проблему с зомби с помощью операций и обнаружил, что вызов метода cancelAllOperations в очереди не отменяет данную операцию, и на самом деле очередь операций пуста, хотя операция все еще выполняется. *
Структура представляла собой 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, вызывая init и viewDidAppear, начиная операцию.
- [Операции mOperationQueue] содержит ровно один элемент;
- Вскоре после этого операция входит в основной и
- Пользователь покидает viewcontroller до завершения операции.
- dealloc вызывается в viewcontroller (поскольку операция сохраняет слабую ссылку)
- [Операции mOperationQueue] содержат ноль (!) Элементов
- cancelAllOperations отправляется в очередь операций
- [Отмена NSOperation] не вызывается, в результате чего отображается поддельное состояние, видимое приложению.
- dealloc заканчивает
- операция завершена
- isCancelled возвращает false, что приводит к вызову зомби
Документация NSOperationQueue, однако, прямо заявляет, что «Операции остаются в очереди, пока они не завершат свою задачу». что выглядит как нарушение договора.
Я исправил сбой, сохранив ссылку на операцию и вручную отправив отмену, но я хотел бы знать, почему оригинальный подход не работает для предотвращения дальнейших проблем. Может кто-нибудь пролить свет на это?
Заранее спасибо.