web-dev-qa-db-ja.com

KVO-オブジェクトがオブザーバーかどうかを確認する方法は?

addObserver:forKeyPath:options:context:を使用してオブジェクトの値を監視する場合、最終的には後でクリーンアップするためにそのオブジェクトでremoveObserver:forKeyPath:を呼び出します。それを行う前に、オブジェクトが実際にそのプロパティを監視しているかどうかを確認することは可能ですか?

私はコードで、オブジェクトが必要なときにのみオブザーバーを削除するようにしましたが、オブザーバーが自身を2回削除しようとする可能性がある場合があります。私はこれを防ぐために取り組んでいますが、念のために、自分のコードが実際に何かのオブザーバーであるかどうかを最初に確認する方法があるかどうかを把握しようとしています。

39
Josh Buhler

[...]オブジェクトが実際にそのプロパティを監視しているかどうかを確認できますか?

いいえ。KVOを扱うときは、常に次のモデルを念頭に置いてください。

観測を確立するとき、その正確な観測を削除する責任があります。観測はそのコンテキストによって識別されます。したがって、コンテキストは一意である必要があります。通知を受信するとき(およびLionでは、オブザーバーを削除するとき)、パスではなくコンテキストを常にテストする必要があります。

監視対象オブジェクトを処理するためのベストプラクティスは、監視対象オブジェクトのセッターで監視を削除して確立することです。

static int fooObservanceContext;

- (void)setFoo:(Foo *)foo
{
    [_foo removeObserver:self forKeyPath:@"bar" context:&fooObservanceContext];

    _foo = foo; // or whatever ownership handling is needed.

    [foo addObserver:self forKeyPath:@"bar" options:0 context:&fooObservanceContext];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (context == &fooObservanceContext) {
        // handle change
    } else {
        // not my observer callback
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
    }
}

- (void)dealloc
{
    self.foo = nil; // removes observer
}

KVOを使用する場合、オブザーバーとオブザーバの両方のオブジェクトが、オブザベーションが行われている限り生きていることを確認する必要があります。

オブザベーションを追加する場合、これと同じオブザベーションを1回だけ削除することのバランスを取る必要があります。 KVOを使用しているのはあなただけだと思い込まないでください。フレームワーククラスは、独自の目的でKVOを使用する場合があるため、コールバックのコンテキストを常に確認してください。

最後に指摘したいのは、監視対象のプロパティがKVOに準拠していることです。 何も観察することはできません

44
Nikolai Ruhe

NSKeyValueObservingプロトコルの一部は次のとおりです。

 - (void *)observationInfo

オブザーバーをリストする必要があります。

[〜#〜] edit [〜#〜]デバッグのみに役立ちます。

26
Rayfleck

これは客観的な質問です。しかし、多くの人がSwift/objective-cを一緒に使用しているため、古いバージョンのKVOよりもSwift4の新しいAPIの利点を指摘したいと思いました。

KVOでaddObserverを複数回実行すると、変更ごとに、自分がオブザーバーとして追加した現在の回数と同じ数のobserveValueが取得されます。

  • そして、自分自身を削除するにはhaveを追加した回数だけremoveObserverを呼び出します。
  • 追加した数よりも多く削除すると、クラッシュします

Swift4 observeは、はるかにスマートで迅速です!

  • 複数回やっても構いません変更ごとに複数のコールバックを与えることはありません。
  • invalidatetokenは1つで十分です。
  • invalidatオブザーバーを開始する前に実行するか、observeを実行しても何度もクラッシュしません

したがって、質問に具体的に答えるために、新しいSwift4 KVOを使用する場合は、気にする必要はありません。 invalidateを呼び出すだけで大丈夫です。しかし、古いAPIを使用している場合は、ニコライの答えを参照してください

1
Honey