1. 程式人生 > >iOS KVO的原理與使用

iOS KVO的原理與使用

一,概述

KVO,即:Key-Value Observing,它提供一種機制,當指定的物件的屬性被修改後,則物件就會接受到通知。簡單的說就是每次指定的被觀察的物件的屬性被修改後,KVO就會自動通知相應的觀察者了。

觀察者模式的定義:一個目標物件管理所有依賴於它的觀察者物件,並在它自身的狀態改變時主動通知觀察者物件。這個主動通知通常是通過呼叫各觀察者物件所提供的介面方法來實現的。觀察者模式較完美地將目標物件與觀察者物件解耦。

當需要檢測其他類的屬性值變化,但又不想被觀察的類知道,這個時候就可以使用KVO了。

KVO和KVC一樣都依賴於Runtime的動態機制。

KVO底層實現原理解析:

  • 當類A的物件第一次被觀察的時候,系統會在執行期動態建立類A的派生類。我們稱為B。
  • 在派生類B中重寫類A的setter方法,B類在被重寫的setter方法中實現通知機制。
  • 類B重寫會 class方法,將自己偽裝成類A。類B還會重寫dealloc方法釋放資源。
  • 系統將所有指向類A物件的isa指標指向類B的物件。

二,使用方法

系統框架已經支援KVO,所以程式設計師在使用的時候非常簡單。

1. 註冊,指定被觀察者的屬性,

/*
* @param keyPath 就是要觀察的屬性值
* @param options 給你觀察鍵值變化的選擇
* NSKeyValueObservingOptionNew = 0x01, 新值
* NSKeyValueObservingOptionOld = 0x02, 舊值
* @param context 方便傳輸你需要的資料
*/

-(void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;

2. 實現回撥方法

/* * 當物件的屬性發生改變會呼叫該方法
* @param keyPath 監聽的屬性
* @param object 監聽的物件
* @param change 新值和舊值
* @param context 額外的資料
*/

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

3. 移除觀察

- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

三,例項:

假設一個場景,股票的價格顯示在當前螢幕上,當股票價格更改的時候,實時顯示更新其價格。

1.定義DataModel,

@interface StockData : NSObject {
    NSString * stockName;
    float price;
}

@end

@implementation StockData

@end

2.定義此model為Controller的屬性,例項化它,監聽它的屬性,並顯示在當前的View裡邊

- (void)viewDidLoad
{
    [super viewDidLoad];

    stockForKVO = [[StockData alloc] init];
    [stockForKVO setValue:@"searph" forKey:@"stockName"];
    [stockForKVO setValue:@"10.0" forKey:@"price"];
    [stockForKVO addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];

    myLabel = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 100, 30 )];
    myLabel.textColor = [UIColor redColor];
    myLabel.text = [stockForKVO valueForKey:@"price"];
    [self.view addSubview:myLabel];

    UIButton * b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    b.frame = CGRectMake(0, 0, 100, 30);
    [b addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:b];
}

3.當點選button的時候,呼叫buttonAction方法,修改物件的屬性

-(void) buttonAction
{
    [stockForKVO setValue:@"20.0" forKey:@"price"];
}

4. 實現回撥方法

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if([keyPath isEqualToString:@"price"])
    {
        myLabel.text = [stockForKVO valueForKey:@"price"];
    }
}

5.增加觀察與取消觀察是成對出現的,所以需要在最後的時候,移除觀察者

- (void)dealloc
{
    [stockForKVO removeObserver:self forKeyPath:@"price"];
}

四,小結

KVO這種編碼方式使用起來很簡單,很適用與datamodel修改後,引發的UIVIew的變化這種情況,就像上邊的例子那樣,當更改屬性的值後,監聽物件會立即得到通知。