KVO

KVO

Key-Value observing(KVC),鍵值觀察女揭,它提供一種機(jī)制屏鳍,當(dāng)被觀察的對(duì)象的屬性被修改后,KVO會(huì)自動(dòng)通知相對(duì)應(yīng)的觀察者挖函。接下來我會(huì)演示一下KVO的例子状植。

觀察Model里的屬性變化

廢話不多說,直接上代碼∨不現(xiàn)有Model: Person

@interface Person : NSObject

@property (nonatomic, copy) NSString *name;

@property (nonatomic, strong) NSNumber *age;

@end

我們來通過KVO動(dòng)態(tài)監(jiān)聽Person中name, age的變化浅萧。這里是標(biāo)準(zhǔn)的操作流程:

第一步:注冊(cè),指定被觀察者對(duì)象

[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];

[self.person addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew context:nil];

第二步:實(shí)現(xiàn)回調(diào)方法

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

if ([keyPath isEqualToString:@"name"]) {

self.titleLabel.text = self.person.name;

}

}

第三步:移除觀察者哲思,如果沒有移除觀察者,會(huì)引發(fā)異常吩案,這也是KVO不方便的一點(diǎn)

[self.person removeObserver:self forKeyPath:@"name"];

[self.person removeObserver:self forKeyPath:@"age"];

如上:實(shí)現(xiàn)這三部棚赔,一個(gè)簡(jiǎn)單的KVO,我們就搞定了徘郭。是不是 so easy!

經(jīng)典案例

下拉刷新靠益,通過監(jiān)聽 frame 來改變動(dòng)畫效果

創(chuàng)建 TableViewController,自定義UIRefreshControl残揉,在這里邊監(jiān)聽 frame胧后,來改變動(dòng)畫效果

[self addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew context:nil];

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

if (self.frame.origin.y > 0 ) {return;}

if (self.frame.origin.y < -60 ) {

[UIView animateWithDuration:0.5 animations:^{

self.refreshView.arrowView.transform = CGAffineTransformRotate(self.refreshView.arrowView.transform, M_PI);

self.refreshView.titleLabel.text = @"下拉刷新";

} completion:^(BOOL finished) {

}];

}else if (self.frame.origin.y >= -60){

[UIView animateWithDuration:0.5 animations:^{

self.refreshView.arrowView.transform = CGAffineTransformRotate(self.refreshView.arrowView.transform, M_PI);

self.refreshView.titleLabel.text = @"松手返回";

} completion:^(BOOL finished) {

}];

}

}

關(guān)聯(lián)依賴

是不是說,掌握了第一部分抱环,我們就能是使用KVO了壳快。答案是肯定的,如果各位看官不想在繼續(xù)了解的話镇草,請(qǐng)按左上角【返回】按鈕眶痰。哈哈哈村象,開玩笑啦描馅,接下來給大家介紹一個(gè)好玩的例子,關(guān)聯(lián)依賴母蛛。

廢話不多說因宇,直接上代碼七婴,我就是這么痛快

假設(shè)有Person類,其中有三個(gè)屬性: firstName, lastName, fullName察滑,那當(dāng)我們要?jiǎng)討B(tài)的觀察 fullName時(shí)打厘,怎么辦呢。我們都知道fullName 是跟 firstName, lastName有關(guān)聯(lián)的杭棵,依據(jù)上文說到的方法婚惫,這時(shí)我們要注冊(cè)三個(gè)觀察對(duì)象氛赐,這很low,這時(shí)先舷,依賴關(guān)聯(lián)可以登場(chǎng)了艰管。

第一步: 重寫 + (NSSet *)keyPathsForValuesAffection<鍵名>方法

// 設(shè)置 fullName 依賴 firstName, lastName

// 注冊(cè)觀察 fullName, 當(dāng)firstName, lastName變化時(shí)蒋川,就能收到通知

+ (NSSet *)keyPathsForValuesAffectingFullName {

NSSet *set = [NSSet setWithObjects:@"firstName",@"lastName", nil];

return set;

}

第二步:之后操作同上

[self.person addObserver:self forKeyPath:@"fullName" options: NSKeyValueObservingOptionPrior context:nil];

這時(shí)牲芋,我們?cè)诟淖?firstName, lastName中任意一個(gè)屬性值的時(shí)候,我們通過注冊(cè)的 fullName 都可以獲取到捺球,是不是很神奇案灼帧!

手動(dòng)通知 VS 自動(dòng)通知

有沒有感覺KVO很神奇氮兵,但實(shí)際上發(fā)生的事情是:當(dāng) name 的實(shí)例 -setName: 方法被調(diào)用的時(shí)候裂逐,系統(tǒng)自動(dòng)在之前與之后幫我們添加了部分代碼:

- (void)willChangeValueForKey:(NSString *)key

- (void)didChangeValueForKey: (NSString *)key

他們分別會(huì)在 setName: 中的代碼之前與之后調(diào)用。有些時(shí)候泣栈,我們需要自己來控制是否發(fā)送通知卜高,或者改變某些特殊的數(shù)據(jù)內(nèi)容,就可以做如下操作:

第一步:重寫 setter 方法南片,并手動(dòng)添加通知前后方法

-(void)setName:(NSString *)name {

[self willChangeValueForKey:@"name"];

// 這里可以對(duì)處理特別操作

_name = [NSString stringWithFormat:@"%@123", name];

[self didChangeValueForKey:@"name"];

}

第二步: 實(shí)現(xiàn) automaticallyNotifiesObserversForKey掺涛,return NO

// 通過此方法,決定是否發(fā)送通知

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {

// 如果是 name 則疼进,手動(dòng)發(fā)送通知

if ([key isEqualToString:@"name"]) {

return NO;

}

// 其他薪缆,則自動(dòng)發(fā)送通知

return [super automaticallyNotifiesObserversForKey:key];

}

參數(shù)詳解

addObserver:forKeyPath: options:context:

observer:觀察者,一般都是 self(本身)

keyPath: 被觀察的屬性名稱伞广,例如上文中的 @"name", @"age"

options: 觀察屬性的新值拣帽、舊值等的一些配置(枚舉值)

NSKeyValueObservingOptionNew? ? = 0x01,

NSKeyValueObservingOptionOld? ? = 0x02,

NSKeyValueObservingOptionInitial = 0x04,

NSKeyValueObservingOptionPrior? = 0x08

四個(gè)值的含義如下:

NSKeyValueObservingOptionNew:接收方法中使用change參數(shù)傳入變化后的新值,鍵為:NSKeyValueChangeNewKey赔癌;

NSKeyValueObservingOptionOld:接收方法中使用change參數(shù)傳入變化前的舊值诞外,鍵為:NSKeyValueChangeOldKey;

NSKeyValueObservingOptionInitial:注冊(cè)之后立刻調(diào)用接收方法灾票,如果配置了NSKeyValueObservingOptionNew峡谊,change參數(shù)內(nèi)容會(huì)包含新值,鍵為:NSKeyValueChangeNewKey刊苍;

NSKeyValueObservingOptionPrior:如果加入這個(gè)參數(shù)既们,接收方法會(huì)在變化前后分別調(diào)用一次,共兩次正什,可以分別獲取變化前后不通的值

context: 上下文啥纸,可以為kvo的回調(diào)方法傳值

observeValueForKeyPath: ofObject: change:context:

keyPath:屬性名稱,通過它可以獲取到當(dāng)前觀察的是哪個(gè)屬性

object:被觀察的對(duì)象

change:變化前后的值都存儲(chǔ)在change字典中

context:注冊(cè)觀察者時(shí)婴氮,context傳過來的值

線程

KVO 是線程同步的斯棒,發(fā)生變化的值與所觀察的值在同一個(gè)線程上盾致。

我們可以在改變被觀察對(duì)象的值時(shí),來開啟一個(gè)線程荣暮,在回調(diào)方法中查看是否同屬于同一個(gè)線程庭惜。

[self performSelectorInBackground:@selector(changeValue) withObject:nil];

- (void)changeValue {

self.starThreadLabel.text = [NSString stringWithFormat:@"開啟線程:%@", [NSThread currentThread]];

self.person.name = @"我是子線程"

}

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

NSLog(@"當(dāng)前線程為:%@",[NSThread currentThread]);

}

PS: 以上都是一家之言,望各位看官多加實(shí)驗(yàn)來驗(yàn)證穗酥,非喜勿噴护赊。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市砾跃,隨后出現(xiàn)的幾起案子骏啰,更是在濱河造成了極大的恐慌,老刑警劉巖抽高,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件判耕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡厨内,警方通過查閱死者的電腦和手機(jī)祈秕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雏胃,“玉大人,你說我怎么就攤上這事志鞍〔t亮!?“怎么了?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵固棚,是天一觀的道長(zhǎng)统翩。 經(jīng)常有香客問我,道長(zhǎng)此洲,這世上最難降的妖魔是什么厂汗? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮呜师,結(jié)果婚禮上娶桦,老公的妹妹穿的比我還像新娘。我一直安慰自己汁汗,他們只是感情好衷畦,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著知牌,像睡著了一般祈争。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上角寸,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天菩混,我揣著相機(jī)與錄音忿墅,去河邊找鬼。 笑死沮峡,一個(gè)胖子當(dāng)著我的面吹牛疚脐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播帖烘,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼亮曹,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了秘症?” 一聲冷哼從身側(cè)響起照卦,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎乡摹,沒想到半個(gè)月后役耕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡聪廉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年瞬痘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片板熊。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡框全,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出干签,到底是詐尸還是另有隱情津辩,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布容劳,位于F島的核電站喘沿,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏竭贩。R本人自食惡果不足惜蚜印,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望留量。 院中可真熱鬧窄赋,春花似錦、人聲如沸肪获。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽孝赫。三九已至较木,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間青柄,已是汗流浹背伐债。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工预侯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人峰锁。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓萎馅,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親虹蒋。 傳聞我的和親對(duì)象是個(gè)殘疾皇子糜芳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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