hirakiucの日記

いろいろ

Key-Value Observing

"objcでKey-Value Observingしたいのだけど、observeValueForKeyPath:ofObject:change:contextメソッドでsuperを呼び出すのはどんなとき?" という話。

Key-Value Observingの方法とかは、他の方の分かりやすい記事を参照ください。

observeValueForKeyPath:ofObject:change:contextの書き方

Key-Value Observingするとき、監視する側はこのメソッドが呼ばれて通知される様子。

// NSKeyValueObserving Protocol
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;

googleさんで探すと良く見つかるのはこんなコード

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
  if ([keyPath isEqualToString:@"tintColor"]) {
    // tintColorに変更があったときのコード
  }
}

他には、superを呼び出してるコードも見つけた。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
   // なにかのコード
   [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}

どんなときにsuperを呼ぶ必要があるのか気になったので探してみた。

NSInternalInconsistencyException when using KVO

自分が監視しているkeyPathの場合はsuperを呼び出すべきじゃないね (NSInternalInconsistencyExceptionが起きるから)という話の様子。

で、自分で監視したkeyPathかどうかを判別する一つの方法として、 「observerを登録する際にcontextも一緒に登録しておくと、observeValueForKeyPath:ofObject:change:contextメソッドのcontextで判断できる」という内容ぽい。

// enabled ARC

// observerを追加するとき
[observedObject addObserver:self forKeyPath:@"tintColor" options:0 context:(__bridge void *)self];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
   if (context == (__bridge void *)self) {
     // 監視してるkeyPath毎のコード
  } else {
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
  }
}
// 

一つ疑問が解消した。