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

The reason your are seeing this problem is that you are not using the context pointer. When you add or remove an observer, pass a context pointer. In your observeValueForKeyPath:ofObject:change:context: , check the context point to make sure the observation being passed belongs to you. If not, call super. It's possible to use self as the context point, or you can take the address of a static string, etc. Here is an example:

Adding the observer:

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

Handling the change notification:

- (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];
    }
}

Removing the observer:

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

Because your code was not able to pass one of the notifications to super in observeValueForKeyPath:ofObject:change:context:, that notification went in but never came out. This is why you got that exception.

It unfortunate that many of the Key-Value Observing examples available on The IntarWebs do not do this correctly and/or pass NULL as the context pointer (even Apple's documentation does this).

于 2014-09-16T02:10:59.003 に答える