NSOperation KVO проблема - PullRequest
       13

NSOperation KVO проблема

0 голосов
/ 08 июля 2010

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

- (void)observeValueForKeyPath:(NSString *)keyPath 
                      ofObject:(id)object 
                        change:(NSDictionary *)change 
                       context:(void *)context
{
  if([keyPath isEqual:@"isFinished"] && _operation == object)
  {  
    NSLog(@"Our Thread Finished!");
    [_operation removeObserver:self forKeyPath:@"isFinished"];
    [self performSelectorOnMainThread:@selector(showDialog) withObject:nil waitUntilDone:YES];
  } 
}

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

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<Settings: 0x21b970>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled.
Key path: isFinished

Я прекрасно понимаю, что поскольку я пытаюсь делать другие вещи в основном потоке, из-за чего происходит вызов основного потока:

[self performSelectorOnMainThread:@selector(showDialog) withObject:nil waitUntilDone:YES];

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

Это действительно возможно?

Спасибо заранее.

Ответы [ 2 ]

0 голосов
/ 16 сентября 2014

Причина, по которой вы видите эту проблему, заключается в том, что вы не используете указатель context. Когда вы добавляете или удаляете наблюдателя, передайте указатель контекста. В вашем observeValueForKeyPath:ofObject:change:context: проверьте контекстную точку, чтобы убедиться, что передаваемое наблюдение принадлежит вам. Если нет, звоните супер. Можно использовать self в качестве точки контекста, или вы можете взять адрес статической строки и т. Д. Вот пример:

Добавление наблюдателя:

[sample addObserver:self forKeyPath:@"finished" options:[self observationOptions] context:(void *)self];

Обработка уведомления об изменении:

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context == (__bridge void *)self){
        if ([keyPath isEqualToString:@"finished"]){
            // Handle the change here.
        }
    } else {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

Удаление наблюдателя:

[sample removeObserver:self forKeyPath:@"finished" context:(void *)self];

Поскольку ваш код не смог передать одно из уведомлений super в observeValueForKeyPath:ofObject:change:context:, это уведомление пришло, но так и не вышло. Вот почему вы получили это исключение.

К сожалению, многие из примеров наблюдения значения ключа, доступных на IntarWebs, делают это неправильно и / или передают NULL в качестве указателя контекста (даже документация Apple делает это).

0 голосов
/ 12 июля 2010

Если вам может потребоваться Mac OS X 10.6 Snow Leopard или (я думаю) iPhone OS 3.0, вы можете полностью избежать KVO для этого. Просто создайте другую операцию для работы, которую вы хотите выполнить в главном потоке, добавьте операцию, которой она должна следовать в качестве зависимости, а затем поместите операцию основного потока в основную очередь:

NSBlockOperration *mainThreadOp = [NSBlockOperation blockOperationWithBlock:^{
    [self showDialog];
}];
[mainThreadOp addDependency:backgroundOp];
[[NSOperationQueue mainQueue] addOperation:mainThreadOp];

NSOperation поддерживает зависимости между операциями в разных очередях. Только будьте осторожны, чтобы не сделать операции в разных очередях взаимозависимыми, потому что это приведет к взаимоблокировке.

...