Как проверить, завершено ли NSOperationQueue и не завершилась ли какая-либо операция? - PullRequest
2 голосов
/ 18 октября 2011

Я пытаюсь проанализировать некоторые XML-файлы в фоновом режиме, чтобы пользовательский интерфейс не зависал.Я должен проверить две вещи:

  • NSOperationQueue завершен?
  • NSOperation - синтаксический анализ не удалось?

У меня есть класс, который подклассы NSOperation иделегат вызывается, если разбор не удался.Операции в очереди ограничены одной одновременно.

Моя проблема в том, что я не могу полагаться на тот факт, что сообщение об ошибке выполнено до того, как я получу сообщение об окончании очереди.Иногда я не получаю сообщение об ошибке до того, как получу готовое сообщение.Тогда, например, у меня есть следующий порядок:

Операция 1 Успешная операция 2 Успешная операцияКоличество завершено Операция 3 Сбой

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

Вот некоторые части моего кода:

//XMLOperation.m
- (void)main {    
    NSLog(@"Operation started");

    if ([self parseXML]) {
            [self performSelectorOnMainThread:@selector(finishedXMLParsing) withObject:nil waitUntilDone:NO];
        } else {
            [self performSelectorOnMainThread:@selector(failedXMLParsing) withObject:nil waitUntilDone:NO];
        }
    }
    NSLog(@"Operation finished");
}


//StartController.m
[self.xmlParseQueue addObserver:self forKeyPath:@"operations" options:0 context:NULL];

...

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
                         change:(NSDictionary *)change context:(void *)context
{
    if (object == self.xmlParseQueue && [keyPath isEqualToString:@"operations"]) {
        if ([self.xmlParseQueue.operations count] == 0) {
            // Do something here when your queue has completed
            NSLog(@"queue has completed");
        }
    }
    else {
        [super observeValueForKeyPath:keyPath ofObject:object 
                               change:change context:context];
    }
}

Ответы [ 2 ]

2 голосов
/ 18 октября 2011

Это, вероятно, происходит из-за того, что ваше уведомление KVO для свойства operations очереди не обязательно доставляется в главный поток, в то время как ваши законченные / неудачные уведомления.

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

0 голосов
/ 26 августа 2015

Возобновите этот вопрос и вставьте мое решение для кода здесь.

void RunInMainThread(void (^block)(void))
{
    if (!block) {
        return;
    }

    if ([NSThread isMainThread]) {
        block();
    } else {
        dispatch_async(dispatch_get_main_queue(), block);
    }
}

@interface MyOperationQueue : NSOperationQueue

@property (nonatomic, assign) NSUInteger totalCount;
@property (nonatomic, copy) dispatch_block_t allOperationCompletionBlock;

@end

@implementation MyOperationQueue

- (void)addOperation:(NSOperation *)op
{
    [super addOperation:op];
    __weak typeof(self) weakSelf = self;

    self.totalCount++;
    DDLogVerbose(@"Added a operation, total: %ld operation(s).", self.totalCount);

    op.completionBlock = ^ {
        weakSelf.totalCount--;
        DDLogVerbose(@"Finished a operation, left: %ld operation(s).", weakSelf.totalCount);

        if (weakSelf.totalCount == 0) {
            if (weakSelf.allOperationCompletionBlock) {
                RunInMainThread(weakSelf.allOperationCompletionBlock);
            }
        }
    };
}

@ конец

...