Операция завершения NBlock вызывается дважды

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

- (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 в моем тестовом коде, так что это не может быть причиной этого.

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

1 ответ

Решение

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

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

РЕДАКТИРОВАТЬ: Предполагая, что вы переопределяете эти флаги для обеспечения параллелизма, тогда вы должны прочитать примечания в документации

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

Другие вопросы по тегам