iOS-設計模式-觀察者模式-KVO

KVO:atom

Key Value Observe,鍵值觀察:用於監聽屬性的變化,觀察者在鍵值改變時會獲得通知。spa

KVO簡單使用:.net

//KVO的使用也很簡單,就是簡單的3步。
   1.註冊須要觀察的對象的屬性addObserver:forKeyPath:options:context:
   2.實現observeValueForKeyPath:ofObject:change:context:方法,這個方法當觀察的屬性變化時會自動調用
   3.取消註冊觀察removeObserver:forKeyPath:context:
   //不須要在被觀察對象中添加任何代碼

判斷是否有觀察者:指針

[object observationInfo];//若是沒有返回null


KVO內部原理:code

當你觀察一個對象時,一個新的類會動態被建立。這個類繼承自該對象的本來的類,並重寫了被觀察屬性的 setter 方法。天然,重寫的 setter 方法會負責在調用原 setter 方法以前和以後,通知全部觀察對象值的更改。最後把這個對象的 isa 指針 ( isa 指針告訴 Runtime 系統這個對象的類是什麼 ) 指向這個新建立的子類,對象就神奇的變成了新建立的子類的實例。server

原來,這個中間類,繼承自本來的那個類。不只如此,Apple 還重寫了 -class 方法,企圖欺騙咱們這個類沒有變,就是本來那個類對象

簡而言之就是:blog

一、當一個object有觀察者時,動態建立這個object的類的子類繼承

二、對於每一個被觀察的property,重寫其set方法rem

三、在重寫的set方法中調用- willChangeValueForKey:和- didChangeValueForKey:通知觀察者

四、當一個property沒有觀察者時,刪除重寫的方法

五、當沒有observer觀察任何一個property時,刪除動態建立的子類

示例:

@interface myPerson : NSObject  
{  
    NSString *_name;  
    int      _age;  
    int      _height;  
    int      _weight;  
}  
@end  
  
@interface testViewController : UIViewController  
@property (nonatomic, retain) myPerson *testPerson;  
  
- (IBAction)onBtnTest:(id)sender;  
@end  
  
- (void)testKVO  
{  
    testPerson = [[myPerson alloc] init];  
      
    [testPerson addObserver:self forKeyPath:@"height" options:NSKeyValueObservingOptionNew context:nil];  
    /*
    NSKeyValueObservingOptionNew 把更改以前的值提供給處理方法
    NSKeyValueObservingOptionOld 把更改以後的值提供給處理方法
    NSKeyValueObservingOptionInitial 把初始化的值提供給處理方法,一旦註冊,立馬就會調用一次。一般它會帶有新值,而不會帶有舊值。
    NSKeyValueObservingOptionPrior 分2次調用。在值改變以前和值改變以後
    */
}  
  
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context  
{  
    if ([keyPath isEqualToString:@"height"]) {  
        NSLog(@"Height is changed! new=%@", [change valueForKey:NSKeyValueChangeNewKey]);  
    } else {  
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];  
    }  
}  
  
- (IBAction)onBtnTest:(id)sender {  
    int h = [[testPerson valueForKey:@"height"] intValue];      
    [testPerson setValue:[NSNumber numberWithInt:h+1] forKey:@"height"];  
    NSLog(@"person height=%@", [testPerson valueForKey:@"height"]);  
}  
  
- (void)dealloc  
{  
    [testPerson removeObserver:self forKeyPath:@"height" context:nil];  
    [super dealloc];  
}

上述講解:

第一段代碼聲明瞭myPerson類,裏面有個_height的屬性。在testViewController有一個testPerson的對象指針。
      在testKVO這個方法裏面,咱們註冊了testPerson這個對象height屬性的觀察,這樣當testPerson的height屬性變化時,會獲得通知。在這個方法中還經過NSKeyValueObservingOptionNew這個參數要求把新值在dictionary中傳遞過來。
      重寫了observeValueForKeyPath:ofObject:change:context:方法,這個方法裏的change這個NSDictionary對象包含了相應的值。
      須要強調的是KVO的回調要被調用,屬性必須是經過KVC的方法來修改的,若是是調用類的其餘方法來修改屬性,這個觀察者是不會獲得通知的。


來源:

http://blog.csdn.net/sakulafly/article/details/14084183

http://my.oschina.net/caijunrong/blog/510701?fromerr=m1emHKKJ

http://my.oschina.net/zhaodacai/blog/653810?fromerr=YUxKnfQj

相關文章
相關標籤/搜索