Отмена NSOperation из NSOperationQueue вызывает сбой - PullRequest
2 голосов
/ 23 февраля 2012


Я пытаюсь создать класс диспетчера загрузки, который упаковывает все асинхронные операции загрузки (каждая операция имеет свой собственный поток) в подклассе NSOperation, чтобы добавить их позже в NSOperationQueue.Класс менеджера загрузки (одноэлементный) также предоставляет несколько методов для работы с очередью и отмены операций, соответствующих некоторым требованиям.
Это шаги, чтобы начать создание класса Class Cluster (Abstract Factory), который возвращает различные виды NSOperation для различных типов общих операций (выгрузка, загрузка, анализ и т. Д.).
Класс, кажется, работает довольно хорошос операциями загрузки, но если в середине этих операций я вызываю метод для отмены операции, операция успешно отменяется, но приложение завершается несколькими операциями позже.Если я не отменяю никаких операций, все работает нормально.Все операции наблюдаются с использованием КВО.Метод удаления операции выглядит следующим образом:

- (void) cancelDownloadOperationWithID:(NSString *)aUUID{
@synchronized(self){
    [self.dowloadQueue setSuspended:YES]; //downloadQueue is an NSOperationQueue
    NSArray * downloadOperations = [self.dowloadQueue operations];
    NSPredicate * aPredicate = [NSPredicate predicateWithFormat:@"SELF.connectionID == %@",aUUID]; //SELF is the signleton instance of the download manager
    NSArray * filteredArray = [downloadOperations filteredArrayUsingPredicate:aPredicate];
    if ([filteredArray count]==0) {
        [self.dowloadQueue setSuspended:NO];
        return;
    } 
    [filteredArray makeObjectsPerformSelector:@selector(cancel)];
    NSLog(@"Cancelled %d operations",[filteredArray count]);
    [self.dowloadQueue setSuspended:NO];
   }
}

Журнал сбоев довольно непонятен, но представляет собой BAD_EXC_ACCESS (возможно, зомби), обратите внимание, что я нахожусь под ARC.1009 *

Может кто-нибудь дать мне совет по этому поводу?
Спасибо Андреа

Ответы [ 3 ]

4 голосов
/ 29 февраля 2012

Ну, ответ был довольно прост.В переопределенном методе -cancel подкласса NSOperation я устанавливал как законченные, так и исполняемые переменные, запускающие надлежащие обратные вызовы KVO.Проблема заключается в том, что операция остается в NSOperationQueue, даже если она отменяется, когда очередь пытается запустить метод -start в NSOperationQueue, который вызвал свой обратный вызов KVO, в котором происходит сбой.

Обходной путь выглядит следующим образом: Если операция была отменена, когда она не выполнялась, вы должны установить конечную переменную равной YES сразу после реализации метода запуска, в противном случае, если она выполнялась, можно установить ее как завершенную.ДА и выполнение НЕТ.

3 голосов
/ 19 марта 2013

Принятый ответ работает для меня. Просто чтобы прояснить ситуацию на случай, если кто-то еще столкнется с этим, я также испытал этот сбой, неправильно установив isFinished внутри моего - cancel, до того, как асинхронная операция начала выполняться.

Вместо того, чтобы сделать это, я переключил свой - cancel на изменение isFinished, только если операция уже была isExecuting, затем в - start я сразу установил isFinished, как предложено здесь. Вуаля, крушение исчезло.

1 голос
/ 12 августа 2016

Вот часть, написанная в swift с использованием двух предыдущих ответов:

override func cancel() {
    super.cancel()

    if executing {
        executing = false
        finished = true
    }

    task.cancel()
}

override func start() {
    if cancelled {
        finished = true
        return
    }

    executing = true

    main()
}

override func main() {
    task.resume()
}
...