2

KVO에 대한 약간의 도움이 필요합니다. 내가하려고하는 것은 트리 컨트롤러에서 무언가가 변경 될 때 메서드를 트리거하는 것입니다.키 - 값 관측 도움말

그래서이 코드를 사용하여 KVO로 등록합니다.

[theObject addObserver: self 
      forKeyPath: @"myKeyPath" 
       options: NSKeyValueObservingOptionNew 
       context: NULL]; 

그러나 키 경로를 변경하면 어떻게 트리거합니까?

또 하나의 질문으로, Observer로서 본인을 추가 할 때 Key Path를 핵심 데이터 모델의 Property로 지정하고 싶습니다. 올바르게 했습니까?

답변

6

observeValueForKeyPath:ofObject:change:context:을 호출하여 호출 할 메소드를 전달하십시오.

@interface Foo : NSObject { 
    NSDictionary *dispatch; 
    ... 
} 
@end 
@implementation Foo 
-(id)init { 
    if (self = [super init]) { 
     dispatch = [[NSDictionary dictionaryWithObjectsAndKeys:NSStringFromSelector(@selector(somethingHappenedTo:with:)),@"myKeyPath",...,nil] retain]; 
     ... 
    } 
} 
... 
- (void)observeValueForKeyPath:(NSString *)keyPath 
      ofObject:(id)object 
      change:(NSDictionary *)change 
      context:(void *)context 
{ 
    SEL msg = NSSelectorFromString([dispatch objectForKey:keyPath]); 
    if (msg) { 
     [self performSelector:msg withObject:object withObject:keyPath]; 
    } 
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
} 
... 

자세한 내용은 "Receiving Notification of a Change"을 참조하십시오.

+0

"NSDictionary dispatch;"는 "NSDictionary * dispatch"여야하지만 그렇지 않으면 좋음 –

+0

D' oh.보다 일반적으로 유용한 접근법을 위해 "performSelector"를 "performSelector : withObject : withObject"로 변경했습니다. – outis

+0

또 하나의 질문입니다. Observer로서 본인을 추가 할 때, Key Path를 핵심 데이터 모델의 Property로 지정하고 싶습니다. 올바르게 수행 했습니까? – Joshua

4

당신은이를 구현해야하고이 호출 될 때 키 패스 변경 :

(void)observeValueForKeyPath:(NSString *)keyPath 
        ofObject:(id)object 
         change:(NSDictionary *)change 
         context:(void *)context; 

더 많은 정보 here.

+0

논외 그래, 잘못된 질문 :( – genesis

5

Google 툴박스 Mac의 GTMNSObject+KeyValueObserving.h 카테고리 또는 적어도 post 블로그에서 영감을 얻은 Michael Ash의 블로그를 살펴 보시기 바랍니다. 기본적으로 수동 KVO를 수행하는 것은 이며 매우이며 API에서 제안한 패턴은 이상적이지 않습니다. API에 (GTMNSObject + KeyValueObserving처럼) 다른 레이어를 추가하는 것이 훨씬 더 편하다. 더 많은 것을 NSNotification API와 유사하게 만들고 미묘한 버그의 근원을 숨 깁니다.

GTMNSObject + KeyValueObserving를 사용하면

[theObject gtm_addObserver:self 
       forKeyPath:@"myKeyPath" 
        selector:@selector(myCallbackSelector:) 
        userInfo:nil 
        options:NSKeyValueObservingOptionNew]; 

을 할 것이다 당신이 -myCallbackSelector:가 전화를받을 때 당신이 필요로 할 수있는 모든 관련 정보를 캡슐화 유형 GTMKeyValueChangeNotification의 인수와 @"myKeyPath" 변경의 값.

이렇게하면 observeValueForKeyPath:ofObject:change:context에 큰 디스패치 테이블을 보유 할 필요가 없으며 (실제로는 카테고리별로 유지 관리됩니다) 또는 슈퍼와 충돌을 피하기 위해 context 포인터를 사용하는 올바른 방법에 대해 걱정해야합니다/서브 클래스 등

+0

재미있는데, 어디에서 코드/프레임 워크를 다운로드해야합니까? – Joshua

+0

http://code.google.com/p/google-toolbox-for-mac/ GTM은 부스트 ​​C++ 라이브러리와 마찬가지로 원하는 아키텍처를 사용합니다. 직접 프로젝트에 원하는 파일/클래스를 포함하는 것이 좋습니다. 공통적 인 포함 사항이 두 개 있습니다. –

3

(이것은 내가 여기서 배운 기술이다 : http://www.bit-101.com/blog/?p=1999)을 observeValueForKeyPath 방법에

[theObject addObserver:self 
      forKeyPath:@"myKeyPath" 
       options:NSKeyValueObservingOptionNew 
       context:@selector(doSomething)]; 

..then처럼, 당신은 '상황'에 방법을 전달할 수

, SEL 선택기 유형으로 변환 한 다음 수행하십시오.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    SEL selector = (SEL)context; 
    [self performSelector:selector]; 
} 

이 같은, 당신은 '변화'사전에 '새로운'키를 사용할 수있는 해봐요 방법으로 데이터를 전달하려면 :

[theObject addObserver:self 
       forKeyPath:@"myKeyPath" 
       options:NSKeyValueObservingOptionNew 
       context:@selector(doSomething:)]; // note the colon 

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
    { 
     SEL selector = (SEL)context; 

     // send the new value of observed keyPath to the method 
     [self performSelector:selector withObject:[change valueForKey:@"new"]]; 
    } 


-(void)doSomething:(NSString *)newString // assuming it's a string 
{ 
     label.text = newString; 
}