0

我正在使用以下函数在 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];

未能被执行。但是这个问题的解决方案是什么,因为我希望既允许用户在发出请求后执行任何操作,又在完成分配给操作的任务后执行计划的操作。

真的有可能吗?

提前谢谢。

4

2 回答 2

0

如果您需要 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 支持不同队列上的操作之间的依赖关系。请注意不要使不同队列上的操作相互依赖,因为这会导致死锁。

于 2010-07-11T22:41:53.130 回答
0

您看到此问题的原因是您没有使用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 in observeValueForKeyPath:ofObject:change:context:,所以该通知进入但从未出现。这就是你得到那个例外的原因。

不幸的是,IntarWebs 上提供的许多 Key-Value Observing 示例没有正确执行此操作和/或NULL作为上下文指针传递(甚至 Apple 的文档也这样做)。

于 2014-09-16T02:10:59.003 回答