2013-05-04 2 views
4

Я работаю над подклассом NSOperation, и я столкнулся с этой очень странной проблемой, так как блок завершения вызывается дважды подряд. Навыки KVO кажутся прекрасными, но завершение Блока все еще странно называется дважды. Неужели я не понимаю NSOperation? В документации сказано, что блок завершения вызывается, когда isFinished становится YES и что происходит только один раз в моем коде:NSOperation completeBlock вызывается дважды

- (void)main { 
    @autoreleasepool { 
     [self willChangeValueForKey:@"isExecuting"]; 
     [self willChangeValueForKey:@"isReady"]; 
     executing = YES; 
     [self didChangeValueForKey:@"isReady"]; 
     [self didChangeValueForKey:@"isExecuting"]; 

     //start the operation 
    } 
} 

Я тогда просто установить completionBlock так:

self.completionBlock = ^{ 
    NSLog(@"Completed"); 
} 

Когда заканчивается этот метод (он называется только один раз, я дважды проверял это)

- (void)completeOperation { 
    [self willChangeValueForKey:@"isExecuting"]; 
    [self willChangeValueForKey:@"isFinished"]; 
    executing = NO; 
    completed = YES; 
    [self didChangeValueForKey:@"isExecuting"]; 
    [self didChangeValueForKey:@"isFinished"]; 
} 

Но завершение блокировки называется дважды и дважды печатает «Консолированный» в консоли.

А вот методы, которые указывают на текущее состояние:

- (BOOL)isReady { 
    if (executing || cancelled || completed) { 
     return NO; 
    } 
    return YES; 
} 
- (BOOL)isCancelled { 
    return cancelled; 
} 

- (BOOL)isConcurrent { 
    return YES; 
} 

- (BOOL)isExecuting { 
    return executing; 
} 

- (BOOL)isFinished { 
    return completed; 
} 

isCancelled никогда не превращается в YES в моем коде тестирования, так что не может быть причиной.

Я действительно не понимаю, почему ComplelockBlock вызывается дважды. Даже при установке блока завершения в ноль из блока завершения его иногда называют дважды, что еще более странно.

ответ

4

Не уверен, что это причина, но по моему опыту нет необходимости переопределять свойства состояния только для чтения. Вы несете ответственность за проверку isCancelled периодически в основном цикле, и если он настроен на спасение из того, что вы делаете, но я считаю, что другие флаги состояния (isReady, isFinished, isExecuting) автоматически учитываются.

Сколько раз это срабатывает, если вы удаляете управление флагом штата и просто выполняете свой процесс в -main?

EDIT: Предположим, что вы перекрывая эти флаги, чтобы разрешить параллелизм, то вы должны прочитать примечания in the docs

Судя по всему, вы никогда не должны переопределить isReady или isCancelled и вместо того, чтобы переопределить -start в соответствии с инструкции в документах.

+0

Да, вы правы! Раньше я неправильно читал документы. Теперь я запускаю пользовательский фоновый поток в -start, и я удаляю переопределение isReady и isCancelled, и теперь он работает, блок завершения вызывается только один раз :) – JonasG

+0

Я согласен, что вы не хотите реализовывать свой собственный 'isReady 'или' isCancelled'. Если вам нужен пользовательский 'isReady', вам нужно вызвать' super': Как говорят документы: «Если вы хотите использовать пользовательские условия для определения готовности вашего рабочего объекта, вы можете переопределить этот метод и вернуть значение, которое точно отражает готовность приемника.Если вы это сделаете, ваша пользовательская реализация должна вызывать супер и включать ее возвращаемое значение в состояние готовности объекта. Ваша пользовательская реализация также должна генерировать соответствующие уведомления KVO для пути ключа isReady ». – Rob

Смежные вопросы