27

キー値通知の登録に使用される次のメソッドでのコンテキストパラメーターの使用は何ですか。ドキュメントは、それを任意のデータセットとして示しているだけです。

addObserver:self forKeyPath:@"selectedIndex" options:NSKeyValueObservingOptionNew context:nil

誰かがその背後にある目的が何であるかを明らかにすることができますか...

4

1 に答える 1

80

この説明が抽象的すぎて理解できないものではないことを願っています。

MyViewControllerのサブクラスであるクラスを作成するとしますUIViewController。のソースコードがありませんUIViewController

ここで、 KVOを使用してのプロパティのMyViewController変更を監視することにしました。したがって、オブザーバーとして自分自身を適切に追加します。centerself.view

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.view addObserver:self forKeyPath:@"center" options:0 context:NULL];
}

- (void)viewDidDisappear:(BOOL)animated {
    [self.view removeObserver:self forKeyPath:@"center"];
    [super viewDidDisappear:animated];
}

ここでの問題は、自分自身をのUIViewControllerオブザーバーとして登録するかどうかがわからないことです。もしそうなら、あなたは2つの問題を抱えているかもしれません:self.viewcenter

  1. ビューの中心が変わると、2回呼び出される場合があります。
  2. UIViewControllerオブザーバーから自分を削除すると、のKVO登録も削除される可能性があります。

UIViewControllerのKVO登録と区別できるオブザーバーとして自分自身を登録する方法が必要です。そこで引数が出てきます。引数として使用していないことが絶対に確実なcontext値を渡す必要があります。登録を解除するときは、同じものを再度使用して、登録を削除するだけで、の登録は削除しないようにします。そして、あなたのメソッドでは、メッセージがあなたのためのものか、あなたのスーパークラスのためのものかを確認するためにをチェックする必要があります。contextUIViewControllercontextcontextUIViewControllerobserveValueForKeyPath:ofObject:change:context:context

context他に何も使用しないを確実に使用する1つの方法は、でstatic変数を作成することですMyViewController.m。次のように、登録および登録解除するときに使用します。

static int kCenterContext;

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [self.view addObserver:self forKeyPath:@"center" options:0 context:&kCenterContext];
}

- (void)viewDidDisappear:(BOOL)animated {
    [self.view removeObserver:self forKeyPath:@"center" context:&kCenterContext];
    [super viewDidDisappear:animated];
}

次に、observeValueForKeyPath:...メソッドで次のように確認します。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context
{
    if (context == &kCenterContext) {
        // This message is for me.  Handle it.
        [self viewCenterDidChange];
        // Do not pass it on to super!
    } else {
        // This message is not for me; pass it on to super.
        [super observeValueForKeyPath:keyPath ofObject:object
            change:change context:context];
    }
}

これで、スーパークラスのKVOが干渉したとしても、干渉しないことが保証されます。また、誰かがMyViewControllerKVOを使用するサブクラスを作成した場合でも、KVOに干渉することはありません。

観察するキーパスごとに異なるコンテキストを使用できることにも注意してください。その後、システムが変更を通知したときに、キーパスをチェックする代わりにコンテキストをチェックすることができます。ポインタの同等性のテストは、文字列の同等性のチェックよりも少し高速です。例:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
    change:(NSDictionary *)change context:(void *)context
{
    if (context == &kCenterContext) {
        [self viewCenterDidChange];
        // Do not pass it on to super!
    } else if (context == &kBackgroundColorContext) {
        [self viewBackgroundDidChange];
        // Do not pass it on to super!
    } else if (context == &kAlphaContext) {
        [self viewAlphaDidChange];
        // Do not pass it on to super!
    } else {
        // This message is not for me; pass it on to super.
        [super observeValueForKeyPath:keyPath ofObject:object
            change:change context:context];
    }
}
于 2012-08-11T20:36:35.953 に答える