代码之家  ›  专栏  ›  技术社区  ›  neha

NSKVO问题

  •  0
  • neha  · 技术社区  · 14 年前

    - (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 回复  |  直到 14 年前
        1
  •  0
  •   Chris Hanson    14 年前

    如果你需要MacOSX10.6SnowLeopard,或者(我认为)iPhoneOS3.0,你可以完全避免KVO。只需为要在主线程上执行的工作创建另一个操作,将它需要遵循的操作添加为依赖项,然后将主线程操作放在主队列上:

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

    NSOperation支持不同队列上的操作之间的依赖关系。请注意不要使不同队列上的操作相互依赖,因为这将导致死锁。

        2
  •  0
  •   quellish    10 年前

    您看到此问题的原因是您没有使用 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];
    

    观察值ath:ofObject:change:context: ,通知进去了,但一直没出来。这就是为什么你有例外。

    不幸的是,IntarWebs上提供的许多关键值观察示例没有正确地执行此操作和/或通过 NULL 作为上下文指针(甚至苹果的文档也会这样做)。