iOS ---觀察者模式

觀察者模式本質(zhì)上時(shí)一種發(fā)布-訂閱模型,用以消除具有不同行為的對(duì)象之間的耦合,通過這一模式,不同對(duì)象可以協(xié)同工作,同時(shí)它們也可以被復(fù)用于其他地方Observer從Subject訂閱通知,ConcreteObserver實(shí)現(xiàn)重現(xiàn)ObServer并將其重載其update方法。一旦SubJect的實(shí)例需要通知Observer任何新的變更,Subject會(huì)發(fā)送update消息來通知存儲(chǔ)在其內(nèi)部類中所注冊(cè)的Observer、在ConcreteObserver的update方法的實(shí)際實(shí)現(xiàn)中,Subject的內(nèi)部狀態(tài)可被取得并進(jìn)行后續(xù)處理。其類圖如下:

觀察者模式.png

由上面我們可以發(fā)現(xiàn)觀察者模式無非在是定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,并且當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變的時(shí)候,所有依賴于它的對(duì)象都會(huì)得到通知且自動(dòng)更新。即如果Subject允許其他觀察者(實(shí)現(xiàn)了觀察者接口的對(duì)象)對(duì)這個(gè)Subject的改變進(jìn)行請(qǐng)閱,當(dāng)Subject發(fā)送了變化,那么Subject會(huì)將這個(gè)變化發(fā)送給所有的觀察者,觀察者就能對(duì)Subject的變化做出更新。其時(shí)序圖如下

觀察者模式2.png

通過上面的觀察我們可以發(fā)現(xiàn)如果用N個(gè)Observer來拓展Subject的行為,這些Observer具有處理存儲(chǔ)在Subject中的信息的特定實(shí)現(xiàn),這樣也就實(shí)現(xiàn)了前面所說的消除不同對(duì)象間的耦合的功能了。
那么了解了這些我們可能就會(huì)更像了解下我們?cè)谑裁磿r(shí)候才會(huì)去使用觀察者模式呢?

  • 當(dāng)需要將改變通知所有的對(duì)象時(shí),而你又不知道這些對(duì)象的具體類型
  • 改變發(fā)生在同一個(gè)對(duì)象中,并需要改變其他對(duì)象將相關(guān)的狀態(tài)進(jìn)行更新且不知道有多少個(gè)對(duì)象。

而同樣的在我們?nèi)粘5拈_發(fā)中在Cocoa Touch框架中的的兩種經(jīng)常打交道的技術(shù)KVO與通知都實(shí)現(xiàn)了觀察者模式,所以下面我們討論的重點(diǎn)也就是基于這兩個(gè)方面的。

通知

小編發(fā)布了一篇文章,地址是:http://www.itdecent.cn/p/2efc71c4188a 里面有通知的基礎(chǔ)用法,這里就不過多的介紹了。

KVO

KVO是Key-Value-Observing的縮寫

通過KVO這種機(jī)制對(duì)象可以通過它得到其他對(duì)象的某個(gè)屬性的變更通知。這種機(jī)制在MVC模式下顯得更為重要,KVO可以讓視圖對(duì)象經(jīng)過控制器觀察模型對(duì)象的變更從而做出更新等操作。
KVO這一機(jī)制是基于NSKeyValueObserving協(xié)議的,Cocoa通過這個(gè)協(xié)議為所有遵循協(xié)議的對(duì)象提供了自動(dòng)觀察屬性變化的能力。在NSObject中已經(jīng)為我們實(shí)現(xiàn)了這一協(xié)議,所以我們不必去實(shí)現(xiàn)這個(gè)協(xié)議。
下圖形象的表示了KVO的一種工作流程:


Screen Shot 2014-06-15 at 3.31.32 PM

為什么要使用KVO?

有的朋友可能會(huì)有疑問,為什么要使用KVO呢?KVO能實(shí)現(xiàn)的我使用Setter方法同樣能實(shí)現(xiàn)啊。其實(shí)不然KVO存在還是有它的價(jià)值的,那么接下來我們細(xì)數(shù)一下KVO的獨(dú)特價(jià)值吧:
1.我們創(chuàng)建一兩個(gè)setter方法感覺沒什么,但是如果要觀察的屬性非常多,那么還能一一重寫setter方法來實(shí)現(xiàn)嗎?想必大家心里已有了答案,但是利用KVO則能很好的解決上述問題。
2.我們自定義的類是很容易改寫setter方法的,但是如果你是用一個(gè)已經(jīng)編譯好了的類庫時(shí)要監(jiān)控其中一個(gè)屬性時(shí)怎么辦?難道還要去重寫setter方法?如果使用KVO則很輕松解決問題。
3.使用KVO能夠方便的記錄變化前的值和變化后的值,不適用KVO你還要自己來解決這些問題。
4.KVO讓你的代碼看起來更加簡(jiǎn)潔清晰易于維護(hù)。

觀察的是,屬性是否執(zhí)行了setter方法或者是是否使用了kvc賦值了,只要有賦值的動(dòng)作,都會(huì)執(zhí)行kvo的回調(diào)方法。如果賦值沒有通過setter方法或者KVC,例如(_name = @"新值"),這個(gè)時(shí)候,不會(huì)觸發(fā)kvo回調(diào)方法

一般KVO崩潰的原因

1.被觀察的對(duì)象銷毀掉了(被觀察的對(duì)象是一個(gè)局部變量)2.觀察者被釋放掉了,但是沒有移除監(jiān)聽 3.注冊(cè)的監(jiān)聽沒有移除掉,又從新注冊(cè)了一遍監(jiān)聽

KVO使用方法

添加觀察者和被觀察者

    //你要觀察那個(gè)對(duì)象,就給那個(gè)對(duì)象添加一個(gè)觀察者
//觀察的是self.view 的backgroundColor屬性 獲取舊值和新值
    //observer:觀察者(觀察self.view對(duì)象屬性的變化)
    //keypath:被觀察屬性的名稱
    //觀察屬性的新值,舊值等的一些配置(枚舉值)
    //content:上下文,可以為kvo的回調(diào)方法傳值
    //注冊(cè)觀察者(添加觀察者)
    [self.view addObserver:self forKeyPath:@"backgroundColor" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; 

//觀察Person類的對(duì)象的name屬性
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

KVO回調(diào)方法

//keyPath:屬性名稱
//object:被觀察的對(duì)象
//change:變化前后的值都存儲(chǔ)在Change字典中
//context:注冊(cè)觀察者的時(shí)候content傳遞過來的值。
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
    //監(jiān)聽了好幾個(gè)屬性,使用keyPath區(qū)分
    //監(jiān)聽了好幾個(gè)view,通過object判斷
    
    //view的背景顏色發(fā)生了變化
    if ([keyPath isEqualToString:@"backgroundColor"]) {
        id oldColor = [change objectForKey:NSKeyValueChangeOldKey];
        NSLog(@"舊值---%@---%@", NSKeyValueChangeOldKey, oldColor);
        id newColor = [change objectForKey:NSKeyValueChangeOldKey];
        NSLog(@"新值---%@---%@", NSKeyValueChangeNewKey, newColor);
    }
   //name屬性發(fā)生變化
    if ([keyPath isEqualToString:@"name"]) {
        id oldName = [change objectForKey:@"old"];
        NSLog(@"oldName == %@", oldName);
        
        id newName = [change objectForKey:@"new"];
        NSLog(@"newName == %@", newName);
    }
}

最后使用完之后釋放掉觀察者 一般在dealloc 或者是viewDidDisappear:方法中釋放掉觀察者

//在視圖已經(jīng)消失,移除監(jiān)聽
- (void)viewDidDisappear:(BOOL)animated {
    //移除監(jiān)聽
    [self.view removeObserver:self forKeyPath:@"name" context:nil];
}
//在ARC下,不能使用[super delloc]
- (void)dealloc {
    //移除監(jiān)聽
    [self.person removeObserver:self forKeyPath:@"name" context:nil];
    self.person = nil;
}

參考文章:http://blog.csdn.net/xdrt81y/article/details/24039163 作者:LoveApp_Han

http://www.itdecent.cn/p/56d9417c3a04 作者:曉風(fēng)沐晨 http://www.itdecent.cn/users/350fee9655f0/latest_articles

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1 場(chǎng)景問題# 1.1 訂閱報(bào)紙的過程## 來考慮實(shí)際生活中訂閱報(bào)紙的過程,這里簡(jiǎn)單總結(jié)了一下,訂閱報(bào)紙的基本流程...
    七寸知架構(gòu)閱讀 4,799評(píng)論 5 57
  • 什么是觀察者模式?當(dāng)A對(duì)B的變化感興趣,需要監(jiān)聽B的狀態(tài)變化,就注冊(cè)為B的觀察者,當(dāng)B發(fā)生變化時(shí)通知A,告知B發(fā)生...
    _Lily閱讀 1,655評(píng)論 2 4
  • 一.什么是觀察者模式? 簡(jiǎn)單的說就是一個(gè)對(duì)象擁有多個(gè)特征,當(dāng)某一個(gè)特征發(fā)生變化時(shí),另外一個(gè)對(duì)象做出相應(yīng)的處理和操作...
    LYSNote閱讀 4,300評(píng)論 0 5
  • KVO即:Key-Value Observing, 直譯為:基于鍵值的觀察者。 它提供一種機(jī)制,當(dāng)指定的對(duì)象的屬性...
    _Lily閱讀 1,058評(píng)論 0 1
  • //聯(lián)系人:石虎QQ:1224614774昵稱:嗡嘛呢叭咪哄 一、觀察者模式優(yōu)點(diǎn): 1.觀察者模式在被觀察者和觀察...
    石虎132閱讀 3,328評(píng)論 0 4

友情鏈接更多精彩內(nèi)容