OC KVO模式

簡介

KVO是Key-Value Observing的簡稱册养,也就是鍵值觀察。和廣播通知一樣压固,是ios中的一種通知機(jī)制捕儒,允許對(duì)象監(jiān)聽另一個(gè)對(duì)象特定屬性的改變,并在改變時(shí)接收到事件。由于KVO的實(shí)現(xiàn)機(jī)制刘莹,所以對(duì)屬性才會(huì)發(fā)生作用,一般繼承自NSObject的對(duì)象都默認(rèn)支持KVO焚刚。

KVO和NSNotificationCenter都是iOS中觀察者模式的一種實(shí)現(xiàn)点弯。區(qū)別在于,相對(duì)于被觀察者和觀察者之間的關(guān)系矿咕,KVO是一對(duì)一的抢肛,而不一對(duì)多的。KVO對(duì)被監(jiān)聽對(duì)象無侵入性碳柱,不需要修改其內(nèi)部代碼即可實(shí)現(xiàn)監(jiān)聽捡絮。

這是一張圖片

喬布斯同學(xué),成績不好沒及格莲镣,但是他計(jì)算機(jī)很牛逼福稳,學(xué)校為了防止他入侵系統(tǒng)修改分?jǐn)?shù),設(shè)置了一個(gè)報(bào)警系統(tǒng)--分?jǐn)?shù)被修改就發(fā)出通知瑞侮。當(dāng)然實(shí)現(xiàn)這個(gè)需求的方法很多的圆,這次就用kvo試試。

首先設(shè)置一個(gè)Model里面放上name和score

#import <Foundation/Foundation.h>

@interface StudentModel : NSObject

@property (nonatomic, copy) NSString *name;
@property float score;

@end

然后就是搞UI和添加觀察者

#import "ViewController.h"
#import "StudentModel.h"

//設(shè)備的寬高
#define SCREENWIDTH       [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT      [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@property (nonatomic, strong) StudentModel *studentModel;
@property (nonatomic, strong) UILabel *scoreLabel;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor darkGrayColor];
    
    // 實(shí)例化并設(shè)置監(jiān)聽
    self.studentModel = [[StudentModel alloc] init];
    [self.studentModel setValue:@"喬布斯" forKey:@"name"];
    [self.studentModel setValue:@"59.0" forKey:@"score"];
    //創(chuàng)建觀察者
/***
*  self.studentModel:被觀察的對(duì)象
*  self:觀察者
*  score:被觀察的鍵
*  options:一個(gè)枚舉半火,后面詳細(xì)介紹
*  context:這里可以傳值
***/
    [self.studentModel addObserver:self forKeyPath:@"score" options:NSKeyValueObservingOptionNew |  NSKeyValueObservingOptionOld context:@"分?jǐn)?shù)被改變了"];
    
    // 界面內(nèi)容
    // 名字
    UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, SCREENWIDTH, 20)];
    nameLabel.text = [NSString stringWithFormat:@"Name:%@", [self.studentModel valueForKey:@"name"]];
    nameLabel.textColor = [UIColor whiteColor];
    nameLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:nameLabel];
    
    // 分?jǐn)?shù)
    self.scoreLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 250, SCREENWIDTH, 20)];
    self.scoreLabel.text = [NSString stringWithFormat:@"Score:%@", [self.studentModel valueForKey:@"score"]];
    self.scoreLabel.textColor = [UIColor whiteColor];
    self.scoreLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:self.scoreLabel];
    
    // 按鈕
    UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake((SCREENWIDTH - 100)/2, 300, 100, 20)];
    [btn setTitle:@"修改分?jǐn)?shù)" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(changeScore) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    
//    [self.studentModel removeObserver:self forKeyPath:@"score"];// 4.移除觀察者
}

// 按鈕響應(yīng)
- (void)changeScore {
    [self.studentModel setValue:@"99.0" forKey:@"score"];
}

這里我們就需要kvo干事情了

// KVO回調(diào)
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"score"]) {
        self.scoreLabel.text = [NSString stringWithFormat:@"Score:%@", [self.studentModel valueForKey:@"score"]];
    }
    NSLog(@"keyPath:%@",keyPath);//被觀察的鍵
    NSLog(@"object:%@",object);//被觀察者
    NSLog(@"context:%@", context);// 通過context獲取被觀察者傳遞的內(nèi)容
    NSLog(@"change:%@", change);// 根據(jù)change的設(shè)置獲取新值越妈、舊值等
    NSLog(@"新值:%@",change[@"new"]);
    NSLog(@"舊值:%@",change[@"old"]);
    
}

點(diǎn)擊按鈕后的輸出結(jié)果為:

2019-08-19 15:31:02.868719+0800 KVODemo[2660:437306] keyPath:score
2019-08-19 15:31:02.868838+0800 KVODemo[2660:437306] object:<StudentModel: 0x600001bc3340>
2019-08-19 15:31:02.868918+0800 KVODemo[2660:437306] context:分?jǐn)?shù)被改變了
2019-08-19 15:31:02.869062+0800 KVODemo[2660:437306] change:{
    kind = 1;
    new = 99;
    old = 59;
}
2019-08-19 15:31:02.869130+0800 KVODemo[2660:437306] 新值:99
2019-08-19 15:31:02.869217+0800 KVODemo[2660:437306] 舊值:59

然后在適當(dāng)?shù)臅r(shí)候移除觀察者

[self.studentModel removeObserver:self forKeyPath:@"score"]

options參數(shù)

在添加觀察者時(shí)有一個(gè)options參數(shù),在回調(diào)獲取變化時(shí)有一個(gè)change參數(shù)钮糖,這兩個(gè)參數(shù)其實(shí)是對(duì)應(yīng)的梅掠,都是用來增加傳遞變化的豐富度。

options參數(shù)可以設(shè)為:

  • NSKeyValueObservingOptionOld:這表示在回調(diào)獲取變化時(shí)可以通過change參數(shù)獲取變化之前的值店归;

  • NSKeyValueObservingOptionNew:這表示在回調(diào)獲取變化時(shí)可以通過change參數(shù)獲取變化后的值阎抒;

  • NSKeyValueObservingOptionInitial:在添加觀察者方法return的時(shí)候就發(fā)出一次通知;

  • NSKeyValueObservingOptionPrior:會(huì)在觀察的值發(fā)生變化前發(fā)出一次通知娱节,變化后還是會(huì)發(fā)出一次通知挠蛉,所以變化一次一共會(huì)得到兩次通知。

change參數(shù)

在使用change的時(shí)候可以通過下面的key來操作:

  • NSKeyValueChangeKindKey:對(duì)應(yīng)NSKeyValueChange的枚舉值
    1: NSKeyValueChangeSetting = 1:說明被觀察的數(shù)據(jù)的setter方法被調(diào)用了肄满;

    2:NSKeyValueChangeInsertion = 2:當(dāng)觀察的數(shù)據(jù)是集合時(shí)谴古,且對(duì)它進(jìn)行insert操作時(shí)會(huì)返回該值;

    3:NSKeyValueChangeRemoval = 3:當(dāng)觀察的數(shù)據(jù)是集合時(shí)稠歉,且對(duì)它進(jìn)行remove操作時(shí)會(huì)返回該值掰担;

    4:NSKeyValueChangeReplacement = 4:當(dāng)觀察的數(shù)據(jù)是集合時(shí),且對(duì)它進(jìn)行replace操作時(shí)會(huì)返回該值怒炸。

  • NSKeyValueChangeNewKey:對(duì)應(yīng)options參數(shù)中的NSKeyValueObservingOptionNew带饱,會(huì)在其中包含觀察的數(shù)據(jù)變化后的新值

  • NSKeyValueChangeOldKey:對(duì)應(yīng)options參數(shù)中的NSKeyValueObservingOptionOld,會(huì)在其中包含觀察的數(shù)據(jù)變化之前得舊值

  • NSKeyValueChangeIndexesKey:當(dāng)NSKeyValueChangeKindKey是2、3勺疼、4的時(shí)候教寂,也就是說是觀察集合數(shù)據(jù)時(shí),這個(gè)key的值是一個(gè)NSIndexSet执庐,包含操作對(duì)象的索引集合

  • NSKeyValueChangeNotificationIsPriorKey:包含一個(gè)布爾值酪耕,如果options的參數(shù)是NSKeyValueObservingOptionPrior,也就是會(huì)通知兩次轨淌,在第一次通知迂烁,也就是改變前的通知時(shí),會(huì)包含這個(gè)key

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末递鹉,一起剝皮案震驚了整個(gè)濱河市盟步,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌躏结,老刑警劉巖却盘,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異窜觉,居然都是意外死亡谷炸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門禀挫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旬陡,“玉大人,你說我怎么就攤上這事语婴∶杳希” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵砰左,是天一觀的道長匿醒。 經(jīng)常有香客問我,道長缠导,這世上最難降的妖魔是什么廉羔? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮僻造,結(jié)果婚禮上憋他,老公的妹妹穿的比我還像新娘。我一直安慰自己髓削,他們只是感情好竹挡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著立膛,像睡著了一般揪罕。 火紅的嫁衣襯著肌膚如雪梯码。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天好啰,我揣著相機(jī)與錄音轩娶,去河邊找鬼。 笑死坎怪,一個(gè)胖子當(dāng)著我的面吹牛罢坝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播搅窿,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼隙券!你這毒婦竟也來了男应?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤娱仔,失蹤者是張志新(化名)和其女友劉穎沐飘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牲迫,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耐朴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盹憎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筛峭。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖陪每,靈堂內(nèi)的尸體忽然破棺而出影晓,到底是詐尸還是另有隱情,我是刑警寧澤檩禾,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布挂签,位于F島的核電站,受9級(jí)特大地震影響盼产,放射性物質(zhì)發(fā)生泄漏饵婆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一戏售、第九天 我趴在偏房一處隱蔽的房頂上張望侨核。 院中可真熱鬧,春花似錦蜈项、人聲如沸芹关。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侥衬。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轴总,已是汗流浹背直颅。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怀樟,地道東北人功偿。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像往堡,于是被迫代替她去往敵國和親械荷。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容