2012-02-23 2 views
2


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

- (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 (зомби, возможно), обратите внимание, что я нахожусь под АРК.

0x00a90ea8 <+0393> jle 0xa90d9f <____NSOQSchedule_block_invoke_0+128> 
0x00a90eae <+0399> mov -0x38(%ebp),%ecx 
0x00a90eb1 <+0402> mov -0x34(%ebp),%esi 
0x00a90eb4 <+0405> mov (%esi,%ecx,1),%ecx 
0x00a90eb7 <+0408> mov -0x40(%ebp),%esi 
0x00a90eba <+0411> cmpb $0x0,(%ecx,%esi,1) 
0x00a90ebe <+0415> jne 0xa90d9f <____NSOQSchedule_block_invoke_0+128> 
0x00a90ec4 <+0421> mov (%edi,%eax,1),%esi 
0x00a90ec7 <+0424> mov (%esi,%edx,1),%ebx 
0x00a90eca <+0427> mov %ebx,-0x2c(%ebp) 
0x00a90ecd <+0430> mov -0x44(%ebp),%ebx 
0x00a90ed0 <+0433> cmpl $0x50,(%esi,%ebx,1) 
0x00a90ed4 <+0437> mov %edi,%ebx 
0x00a90ed6 <+0439> jne 0xa90e96 <____NSOQSchedule_block_invoke_0+375> 
0x00a90ed8 <+0441> mov -0x48(%ebp),%ebx 
0x00a90edb <+0444> cmpb $0x0,(%esi,%ebx,1) 
0x00a90edf <+0448> mov %edi,%ebx 
0x00a90ee1 <+0450> je  0xa90e96 <____NSOQSchedule_block_invoke_0+375> 

Может кто-нибудь дать мне предложение об этом?
Thanx Andrea

ответ

4

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

Работает следующим образом: Если операция была отменена, пока она не выполнялась, вы должны установить закончу var в YES сразу после реализации метода запуска, иначе, если она выполнялась, нормально, чтобы закончить до YES и выполняя NO.

+0

Это кажется очень странным поведением для меня, почему бы очередь держать операции, которые еще не были начаты/в очереди? Спасибо, он исправил мой крах. –

+0

Ну и для меня, но это имеет смысл, мы не обесцениваем, мы просто отменяем операцию. – Andrea

3

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

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

+1

Вы могли бы разместить код для этого ... Спасибо – user1028028

1

Вот кусок в стрижа с использованием двух предыдущих ответов:

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() 
} 
Смежные вопросы