2

我需要KVO的一些幫助,我大約在那裏的一半。我試圖做的是在樹控制器中的某些內容發生變化時觸發一個方法。有關鍵值觀察的幫助

所以我使用此代碼註冊爲KVO。

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

但是,當我正在觀察的關鍵路徑發生變化時,我該如何觸發一種方法?

一個額外的問題,當我將自己添加爲觀察者我希望密鑰路徑是我的核心數據模型中的一個屬性,我是否正確地做到了這一點?

回答

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;」,否則就是好。 – 2009-10-02 16:24:23

+0

D'oh。固定。另外,將「performSelector」更改爲「performSelector:withObject:withObject」,以獲得更普遍有用的方法。 – outis 2009-10-02 16:28:57

+0

有一個額外的問題,當我將自己添加爲觀察者時我想讓關鍵路徑成爲我的核心數據模型中的一個屬性,我是否正確地做了這件事? – Joshua 2009-10-02 16:34:07

4

您應該實現這一點,它就會被調用時的keyPath變化:

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

更多信息here

+0

OffTopic:是的,錯誤的問題:( – genesis 2011-10-10 22:21:47

5

我建議你看看谷歌工具箱For Mac的GTMNSObject+KeyValueObserving.h類別或至少是由Michael Ash創建的博客post。基本上,做手動KVO權利是非常微妙和API建議的模式並不理想。將其他圖層放在API上會更好(如GTMNSObject + KeyValueObserving),這使API更像NSNotification API,並隱藏了一些微妙的錯誤來源。

使用GTMNSObject + KeyValueObserving,你會做

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

和你-myCallbackSelector:將被調用時,在@"myKeyPath"變化與GTMKeyValueChangeNotification類型的參數,它封裝了所有你可能需要的相關信息的價值。

這樣,您不必在observeValueForKeyPath:ofObject:change:context(實際上是由您的類別維護)的大調度表,或者不必擔心使用指針的正確方法以避免與超級衝突/子類等

+0

看起來很有趣,我在哪裏下載代碼/框架? – Joshua 2009-10-02 17:25:16

+0

http://code.google.com/p/google-toolbox-for-mac/ 與提升C++庫類似,GTM就是一個你想要的架構。他們建議你將你想要的文件/類直接包含到你自己的項目中。只有幾個常見的包含。 – 2009-10-02 17:43:04

3

(這是一種技術,我在這裏學到:http://www.bit-101.com/blog/?p=1999

您可以通過該方法在 '語境',像

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

在observeValueForKeyPath方法..then ,你將它轉換爲SEL選擇器類型,然後執行它。

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

如果你想將數據傳遞到你可以使用「新」的關鍵在「變」字典中的doSomething方法,像這樣:

[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; 
}