iOS學習心得之:KVO

weixin_33816300發表於2017-04-30

KVO 是 key/value/observing 的縮寫
個人理解的意思是:當對應的key的值value發生改變時,通知observer觀察者執行一些操作.

基本就是一個觀察者模式,和事件模型一模一樣.

// 當前事件釋出者是 ChangeMyProperty物件
// 當前的事件訂閱者是 MyObserverObj物件.
//
//先淺顯的解釋一下啥是KVO.
    //KVO = key / value / observing.
    //當被被觀察者的某個屬性發生變化的時候,會通知觀察者執行一些事情.
    
    ChangeMyProperty *cp = [[ChangeMyProperty alloc] init];
    //定義觀察者
    MyObserverClass *mc = [[MyObserverClass alloc] init];
    //註冊觀察者
    //當cp的name屬性呼叫setter方法,就會通知mc物件處理相關操作.
    [cp addObserver:mc forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
    
    cp.name = @"張三";
    
    [cp removeObserver:mc forKeyPath:@"name"];

屬性發生改變時的事件響應方法.

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    NSLog(@"被監控的屬性是:%@",keyPath);
    NSLog(@"被監控的物件型別是:%@",[object className]);
    
    NSLog(@"值放生了變化啦!!!");
}

最終結果:

2701794-6a878f7bd5737180.png
KVO事件響應函式輸出的結果

可以看出:
第一個引數是[被監控物件的屬性].
第二個引數是[被監控物件的型別].
也就是所謂的事件釋出者的型別和屬性.

既然是key的value發生改變,那麼一定是在key的setter方法的時候,發出通知.
所以開始嘗試自己模擬最簡單的第一版KVO.

核心思想是:當一個物件的某個屬性發生改變時(也就是呼叫setter方法的時候),通知事件訂閱者執行某些操作.

//事件釋出者的程式碼宣告
#import <Foundation/Foundation.h>

@class ObjObserver;//事件訂閱者

@interface EventSender : NSObject

@property (nonatomic,copy) NSString *name;

- (void)myAddObserver:(ObjObserver*)observer forKeyPath:(NSString *)path;

@end

//事件釋出者的程式碼實現
#import "EventSender.h"
#import "ObjObserver.h"

@interface EventSender ()

@property (nonatomic,strong) ObjObserver *observer;

@end

@implementation EventSender

- (void)myAddObserver:(ObjObserver *)observer forKeyPath:(NSString *)path
{
    //繫結事件響應者
    if(observer == nil) return;
    self.observer = observer;
}

- (void)setName:(NSString *)name
{
    _name = name;
    //在name屬性發生改變時執行事件響應者的相關函式
    if (self.observer != nil) {
        [self.observer methodForKvo:name];
    }
}

@end

事件響應者的相關程式碼

#import "ObjObserver.h"

@implementation ObjObserver

- (void)methodForKvo:(NSString *)value
{
    NSLog(@"模擬KVO變化的第一版成功!");
    NSLog(@"變化的屬性值是:%@",value);
    
}

@end

main.m檔案


#import <Foundation/Foundation.h>
#import "EventSender.h"
#import "ObjObserver.h"

int main(int argc, const char * argv[]) {
    //KVO - key/value/observering
    //當某個物件的某個屬性值發生變化時,會通知觀察者執行某些特定的操作.
    
    //註冊事件釋出者
    EventSender *es = [[EventSender alloc] init];
    
    //註冊KVO觀察者
    ObjObserver *ob = [[ObjObserver alloc] init];
    
    //新增觀察者
    [es myAddObserver:ob forKeyPath:@"name"];
    
    es.name = @"事件釋出者物件者呼叫setter方法";
    
    return 0;
}

最後執行結果截圖:

2701794-a4371ea765e25eb4.png
嘗試實現KVO第一版V1.0

最後粗淺的結論:
KVO本質上,就是兩個物件.
一個事件釋出者,在自己的某些屬性的值發生改變時,通知事件響應者執行某些方法.
一個是事件響應者,被事件釋出者繫結到自己的某些屬性的改變行為上.當屬性發生改變時
被動的被事件釋出者執行相關的函式.

畫一張自己理解的圖:

2701794-72fd14aef71c876b.png
KVO簡單理解