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