2011-07-04 4 views
14

、私が観察していたフレームの変更:このobserveValueForKeyPathの何が問題ですか:ofObject:change:context:implementation?私UIScrollViewのサブクラスで

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    if (object == self && [keyPath isEqualToString:@"frame"]) { 
     [self adjustSizeAndScale]; 
    } 
    if ([UIScrollView instancesRespondToSelector:@selector(observeValueForKeyPath:ofObject:change:context:)]) { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; // Exception 
    } 
} 

しかし、私はこのコードで例外を取得:

[self addObserver:self forKeyPath:@"frame" options:0 context:NULL]; 

マイobserveValueForKeyPath:ofObject:change:context:実装は以下のとおりである

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '<WLImageScrollView: 0x733a440; baseClass = UIScrollView; frame = (0 0; 320 416); clipsToBounds = YES; layer = <CALayer: 0x7346500>; contentOffset: {0, 0}>: An -observeValueForKeyPath:ofObject:change:context: message was received but not handled. 
Key path: frame 
Observed object: <WLImageScrollView: 0x733a440; baseClass = UIScrollView; frame = (0 0; 320 416); clipsToBounds = YES; layer = <CALayer: 0x7346500>; contentOffset: {0, 0}> 
Change: { 
    kind = 1; 
} 
Context: 0x0' 

UIScrollViewはobserveValueForKeyPath:ofObject:change:context:を実装していますが、上記の例外をスローしますか?

observeValueForKeyPath:ofObject:change:context:を正しく実装すれば、興味のある変更を処理し、スーパークラスに関心のある変更を処理することができます。

答えて

12

編集:BJホーマーの答えはおそらくここで取るのがよいでしょう。私はコンテキストパラメータについて忘れてしまった!スーパー実装を呼び出すことにより、書籍であっても、それはseems like実際に問題のフィールドを守らないobserveValueForKeyPath:ofObject:change:context:UIKit上のクラスを呼び出すとNSInternalInconsistency例外をスロー

(ないNSInvalidArgumentExceptionあなたが認識されないセレクターとなるだろう)。私にこれを示唆する例外のキー文字列は "受信されましたが処理されません"です。

私が知る限り、あるオブジェクトが特定のキーパス上の別のオブジェクトを観察しているかどうかを調べる方法はありません。オブジェクトのオブザーバーに関する情報を運ぶと言われている-observationInfoプロパティのような、部分的に文書化された方法があるかもしれませんが、自分ではvoid *です。 super実装を呼び出すか、NSInternalInconsistencyExceptionの特定のタイプを無視する@try/@catch/@finallyブロックを使用していないのいずれか:私はそれを見るよう

だから、次の2つのオプションを持っています。 2番目の選択肢はおそらくより将来性のあるものですが、私は、何らかの探偵作品が最初の選択肢を使ってより満足のいく結果を得ることができたことに感心しています。

+1

あなたは別の事について話しているためにリンク先の記事:スーパークラスはobserveValueForKeyPathを実装していません:ofObject:変更:このように

コンテキスト:.しかし、コードからわかるように、UIScrollViewはそれを実装しています。そうでなければ、スーパーメソッドは呼び出されません。 – an0

+0

メソッドを実装していても、観察できないキーを検出し例外をスローするコードを持つ可能性があります。つまり、NSInternalInconsistency例外は「受信されましたが処理されません」です。これは、インスタンスに送信された「NSInvalidArgumentException」 " –

+1

それは私が求めていることです。ですから、observeValueForKeyPath:ofObject:change:context:のデフォルトの実装はNSObjectで例外をスローしますか?そうであれば、スーパークラスがキー値の変更を通知されるかどうかを検出するために行うことはできません。 – an0

16

オブザーバーを追加するときは、contextの値を追加する必要があります。 -observeValueForKeyPathメソッドで、コンテキストパラメータを確認します。オブザーバーを追加したときに渡したコンテキストでない場合、このメッセージはサブクラス用ではなく、安全にスーパークラスに渡すことができます。 が同じ値のであれば、あなたが意図していることを知っているので、superに渡すべきではありません。

static void *myContextPointer; 

- (void)addSomeObserver { 
    [self addObserver:self forKeyPath:@"frame" options:0 context:&myContextPointer]; 
} 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 
    if (context != &myContextPointer) { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
    else { 
     // This message is for me, do whatever I want with it. 
    } 
}         
+0

'static int myContext;'と '[self addObserver:self forKeyPath:@" frame "options:0 context:&myContext];'のようなことをする方が良いでしょう。このように、指されるアドレスは一意であることが保証されます。 –

+0

ああ、そうです、絶対に 'myContextPointer'だけでなく'&myContextPointer'でなければなりません。しかし、私はなぜ 'int'が' void * 'より優れているのか分かりません。 –

+0

intを使うことについて何も良いことはないと思います。 'static int * myContext; 'と入力するのは、static void * myContext; ( - :あなたは、コンパイラが 'myContext'ではなく'&myContext'を使うべきであることを思い出させてくれます。もし 'myContext'の型が' int'ならばコンパイラは警告を出します –

関連する問題