2011-07-04 2 views
14

, 내가 관찰하고있어 프레임 변경 :이 observeValueForKeyPath : ofObject의 문제점 : 변경 : 컨텍스트 : 구현? 내있는 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:을 구현하지만 위의 예외를 throw한다는 것을 의미합니까?

그렇다면 observeValueForKeyPath:ofObject:change:context:을 올바르게 구현하여 관심있는 변경 사항을 처리하고 관심있는 변경 사항을 처리 할 수있는 방법을 제공하려면 어떻게해야합니까?

답변

12

편집 : BJ Homer의 답변이 아마도 여기에 더 좋은 방법 일 것입니다. 컨텍스트 매개 변수에 대해 모두 잊어 버렸습니다!

에 의해 - 더 - 책, 그것은 실제로 문제의 필드를 준수하지 않는 observeValueForKeyPath:ofObject:change:context:UIKit에 클래스를 호출 seems likeNSInternalInconsistency 예외 (안가 발생합니다 슈퍼 구현을 호출하는 경우에도 NSInvalidArgumentException 당신은 알 수없는 선택으로 얻을 것). 내게 이것을 제안하는 예외의 핵심 문자열은 "수신되었지만 처리되지 않았습니다"입니다.

내가 아는 한, 개체가 주어진 키 경로에서 다른 개체를 관찰하는지 확인할 수있는 잘 문서화 된 방법이 없습니다. 객체의 관찰자에 대한 정보를 전달한다고하는 -observationInfo 속성과 같이 부분적으로 문서화 된 방법이있을 수 있지만 사용자가 직접 가지고있는 것은 void *입니다. super 구현을 호출 또는 NSInternalInconsistencyException의 특정 유형을 무시하는 @try/@catch/@finally 블록을 사용하지 않는 중 하나 내가보기로

그래서, 당신은 두 가지 옵션을 가지고있다. 두 번째 옵션은 미래에 대한 가능성이 더 높지만, 일부 탐정 작업은 첫 번째 옵션을 통해 더 만족스러운 결과를 얻을 수 있다는 점에 직감이 있습니다.

+1

다른 일에 대해 이야기에 링크 된 기사 : : ofObject : 변경 : 슈퍼 클래스가 observeValueForKeyPath 구현하지 않는이 같이

컨텍스트를 :. 하지만 코드에서 볼 수 있듯이 UIScrollView는이를 구현합니다. 그렇지 않으면 super 메서드가 호출되지 않습니다. – an0

+0

메소드를 구현하더라도 관찰되지 않는 키를 검출하여 예외를 throw하는 코드가있을 수 있습니다. 따라서 '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"옵션 : 0 context : & myContext];'와 같은 것을하는 것이 더 낫습니다. 이렇게하면 가리키는 주소가 고유하게 보장됩니다. –

+0

아, 네 말이 맞아, 그것은 단지'myContextPointer'뿐만 아니라'& myContextPointer'이어야한다. 하지만 왜 'int'가'void * '보다 더 나을지 모르겠다. –

+0

int를 사용하는 것이 더 좋을 것이라고 생각하지 않습니다. 'static int * myContext; '를 입력하는 것보다'static int myContext; '를 입력하는 것이 약간 더 짧습니다. (- : 컴파일러에서'myContext'가 아니라'& myContext'를 사용해야한다고 생각할 수도 있습니다 - 만약'myContext'의 타입이'int'이면 컴파일러는 –

관련 문제