十年專注于品牌網(wǎng)站建設(shè) 十余年專注于網(wǎng)站建設(shè)_小程序開發(fā)_APP開發(fā),低調(diào)、敢創(chuàng)新、有情懷!
      南昌百恒網(wǎng)絡(luò)微信公眾號 掃一掃關(guān)注
      小程序
      tel-icon全國服務(wù)熱線:400-680-9298,0791-88117053
      掃一掃關(guān)注百恒網(wǎng)絡(luò)微信公眾號
      掃一掃打開百恒網(wǎng)絡(luò)微信小程序

      百恒網(wǎng)絡(luò)

      南昌百恒網(wǎng)絡(luò)

      ios設(shè)計(jì)模式之觀察者模式

      百恒網(wǎng)絡(luò) 2017-04-05 5378

      上周我們跟隨南昌APP開發(fā)制作公司--百恒網(wǎng)絡(luò)一起學(xué)習(xí)了ios設(shè)計(jì)模式之常用模式和委托模式,今天我們繼續(xù)來學(xué)習(xí)ios設(shè)計(jì)模式之觀察者模式。

      觀察者(Observer)模式也叫發(fā)布/訂閱(Publish/Subscribe)模式,是 MVC( 模型-視圖-控制器)模式的重要組成部分。

      3.1 問題提出

      天氣一直是英國人喜歡討論的話題,而最近幾年天氣也成為中國人非常關(guān)注的話題。我會根據(jù)天氣預(yù)報(bào)決定是坐地鐵還是開車上班,也會根據(jù)天氣預(yù)報(bào)決定明天穿哪件衣服。于是在移動(dòng)公司為我的手機(jī)定制了天氣預(yù)報(bào)短信通知服務(wù),它的工作模型如圖所示。

      定制天氣預(yù)報(bào)短信通知服務(wù)

      定制天氣預(yù)報(bào)短信通知服務(wù)

      每天氣象局將天氣預(yù)報(bào)信息投送給移動(dòng)運(yùn)營商,移動(dòng)運(yùn)營商的短信中心負(fù)責(zé)把天氣預(yù)報(bào)發(fā)送給定制過這項(xiàng)服務(wù)的手機(jī)。

      在軟件系統(tǒng)中,一個(gè)對象狀態(tài)的改變也會連帶影響其他很多對象的狀態(tài)發(fā)生改變。能夠?qū)崿F(xiàn)這一需求的設(shè)計(jì)方案有很多,但能夠做到復(fù)用性強(qiáng)且對象之間匿名通信的,觀察者模式是其中最為適合的一個(gè)。

      3.2 實(shí)現(xiàn)原理

      觀察者模式的類圖如圖所示。 它有4個(gè)角色,具體如下所示。

      抽象主題( Subject )。抽象主題是一個(gè)協(xié)議,它是一個(gè)觀察者集合容器,定義了添加觀察者( attach )方法、移除觀察者( detach )方法和為所有觀察者發(fā)送通知的方法( notifyObserver )。

      抽象觀察者( Observer )。抽象觀察者也是一個(gè)協(xié)議,它有一個(gè)更新( update )方法。

      具體觀察者( ConcreteObserver )。 Observer 協(xié)議的具體實(shí)現(xiàn)。

      具體主題( ConcreteSubject )。 Subject 協(xié)議的具體實(shí)現(xiàn)。

      引入 Subject 和 Observer 這兩個(gè)協(xié)議后,不僅提高了系統(tǒng)的可復(fù)用性,還降低了耦合度。觀察者模式還可以有其他變形,若要深入了解,可以參考GoF。

      觀察者模式的類圖(上圖為Swift版,下圖為Objective-C版)

      觀察者模式的類圖(上圖為Swift版,下圖為Objective-C版)

      3.3 通知機(jī)制和 KVO 機(jī)制

      在Cocoa Touch框架中,觀察者模式的具體應(yīng)用有兩個(gè)——通知(notification)機(jī)制和KVO(Key-ValueObserving)機(jī)制,下面簡要介紹這兩種機(jī)制。

      1. 通知機(jī)制

      通知機(jī)制與委托機(jī)制不同的是,前者是“一對多”的對象之間的通信,后者是“一對一”的對象之間的通信。

      說明:在iOS中,通知一詞多次出現(xiàn)過,歸納一下主要有廣播通知(broadcast notification)、本地通知(localnotification)和推送通知(push notification),本節(jié)介紹的是廣播通知。事實(shí)上,除了名字相似,廣播通知與其他兩個(gè)通知完全不同:廣播通知是Cocoa Touch框架中實(shí)現(xiàn)觀察者模式的一種機(jī)制,它可以在一個(gè)應(yīng)用內(nèi)部的多個(gè)對象之間發(fā)送消息;本地通知和推送通知中的“通知”是給用戶一種“提示”,它的“提示”方式有警告對話框、發(fā)出聲音、振動(dòng)和在應(yīng)用圖標(biāo)上顯示數(shù)字等。 在計(jì)劃時(shí)間達(dá)到時(shí),本地通知由本地iOS發(fā)出。推送通知由第三方程序發(fā)送給蘋果的遠(yuǎn)程服務(wù)器,再由遠(yuǎn)程服務(wù)器推送給iOS的特定應(yīng)用。

      如圖所示,在通知機(jī)制中對某個(gè)通知感興趣的所有對象都可以成為接收者。首先,這些對象需要向通知中心( NSNotificationCenter )發(fā)出addObserver:selector:name:object: 消息進(jìn)行注冊,在投送對象投送通知給通知中心時(shí),通知中心就會把通知廣播給注冊過的接收者。所有的接收者都不知道通知是誰投送的,更不關(guān)心它的細(xì)節(jié)。

      投送對象與接收者是一對多的關(guān)系。接收者如果對通知不再關(guān)注,會給通知中心發(fā)出 removeObserver:name:object:消息解除注冊,以后不再接收通知。

      通知機(jī)制圖

      通知機(jī)制圖

      下面我們介紹一下通知機(jī)制的使用過程。這里我們將7.1節(jié)的模態(tài)視圖案例重新設(shè)計(jì)一下,圖8-15所示,在注冊視圖點(diǎn)擊Save按鈕返回到登錄視圖時(shí),把數(shù)據(jù)回傳給登錄視圖。

      模態(tài)視圖案例

      模態(tài)視圖案例

      登錄視圖控制器 ViewController 作為通知的接收者,注冊視圖控制器 RegisterViewController 作為通知投送對象,如圖所示。

      通知機(jī)制圖

      通知機(jī)制圖

      在ViewController視圖控制器中,注冊通知接收者的代碼如下:

      在ViewController視圖控制器中,注冊通知接收者的代碼

      NSNotificationCenter 是單例模式,創(chuàng)建和獲得共享實(shí)例的方法是 defaultCenter , NSNotificationCenter 的addObserver:selector:name:object:方法能夠 注冊通知。當(dāng)接收到 AppWillTerminateNotification 通知時(shí),就會調(diào)用handleTerminate: 方法。

      解除注冊代碼也類似,通過 NSNotificationCenter 發(fā)出 removeObserver 消息實(shí)現(xiàn)。對于視圖控制器,也可以在didReceiveMemoryWarning 方法中發(fā)出消息,具體代碼如下:

      在didReceiveMemoryWarning 方法中發(fā)出消息,具體代碼

      ViewController中接收通知的方法是 registerCompletion: ,其代碼如下:

      這個(gè)方法可以接收一個(gè) NSNotification類型 的參數(shù)。NSNotification 類中有3個(gè)重要的屬性: name 、 object 和userInfo ,這3個(gè)屬性與通知中心投送方法中的參數(shù)有一定的對應(yīng)關(guān)系,如圖所示。

      NSNotification 類和通知中心中投送方法參數(shù)的關(guān)系

      NSNotification 類和通知中心中投送方法參數(shù)的關(guān)系

      其中 name 是通知的名字, object 是投送通知時(shí)傳遞過來的對象, userInfo 是投送通知時(shí)定義的字典對象,可借助于該參數(shù)傳遞數(shù)據(jù)。

      在 RegisterViewController 視圖控制器中,投送通知的代碼如下:

      在 RegisterViewController 視圖控制器中,投送通知的代碼

      NSNotificationCenter 的投送方法除了代碼中所示外,還有另外兩個(gè)重載方法:

      NSNotificationCenter 的投送方法

      它們可以投送不帶 userInfo 參數(shù)的通知,我們可以根據(jù)需要進(jìn)行選擇。還要注意的是, object 參數(shù)未必是 self對象,我們可以根據(jù)需要傳遞一個(gè)對象,如果接收者不需要,可以將其設(shè)為 nil 。

      當(dāng)我們運(yùn)行代碼,從注冊視圖進(jìn)入登錄視圖后,會在日志中輸出回傳回來的 username 參數(shù)。

      Cocoa和Cocoa Touch框架都提供一些通知,由系統(tǒng)自動(dòng)投送。現(xiàn)在修改 ViewController 類添加系統(tǒng)通知:

      修改 ViewController 類添加系統(tǒng)通知

      修改 ViewController 類添加系統(tǒng)通知

      在 viewDidLoad 方法中,第①~②行代碼是系統(tǒng)注冊通知 UIApplicationDidEnterBackgroundNotification (進(jìn)入到后臺通知)和:

      UIApplicationWillEnterForegroundNotification (回到前臺通知)。第③~④行代碼是接收通知后的事件處理。

      提示 在iOS設(shè)備上可以按Home鍵進(jìn)入后臺,快速按兩次Home鍵可以打開最近使用應(yīng)用列表,點(diǎn)擊應(yīng)用可以使該應(yīng)用重新回到前臺。另外,在Xcode模擬器中沒有Home鍵,點(diǎn)擊Home鍵的操作可以通過組合鍵command+shift+H完成。

      除了應(yīng)用生命周期的不同階段有不同的通知外,很多控件也會在某些事件發(fā)生時(shí)投送通知,例如UITextField控件。在編輯過程的不同階段,UITextField控件會分別發(fā)出如下通知:UITextFieldTextDidBeginEditingNotification 、 UITextFieldTextDidChangeNotification 和 UITextFieldTextDidEndEditingNotification 。

      2. KVO機(jī)制

      KVO不像通知機(jī)制那樣通過一個(gè)通知中心通知所有觀察者對象,而是在對象屬性變化時(shí)通知會被直接發(fā)送給觀察者對象。圖為KVO機(jī)制解析圖。

      可以看到,屬性發(fā)生變化的對象需要發(fā)出消息 addObserver:forKeyPath:options:context: 給注冊觀察者,使觀察者關(guān)注它的某個(gè)屬性的變化。當(dāng)對象屬性變化時(shí),觀察者就會接收到通知,觀察者需要重寫方法 observeValueForKeyPath:ofObject:change:context: 以響應(yīng)屬性的變化。

      KVO機(jī)制圖

      KVO機(jī)制圖

      下面我們來看一個(gè)實(shí)際的案例。我們使用KVO機(jī)制來監(jiān)視應(yīng)用程序的狀態(tài)變化。應(yīng)用程序委托對象

      AppDelegate 的 appStatus 屬性是要觀察的屬性。 AppDelegate 的代碼如下:

      AppDelegate的代碼

      上述代碼中第①行的 appStatus 屬性是需要觀察的屬性,在Swift版中它的定義上必須要加 dynamic,以表示該屬性是在運(yùn)行時(shí)動(dòng)態(tài)派發(fā)的。第②行代碼用于定義觀察者AppStatusObserver , AppStatusObserver 是我們的自定義類,它負(fù)責(zé)觀察 appStatus 屬性的變化。第③行代碼用于創(chuàng)建 AppStatusObserver 對象。

      第④行代碼是關(guān)鍵,addObserver:forKeyPath:options:context: 語句告訴觀察者( AppStatusObserver )開始觀察 AppDelegate 的 appStatus 屬性變化,其中參數(shù) addObserver 是觀察者對象; forKeyPath 是被關(guān)注對象的屬性;options 是為屬性變化設(shè)置的選項(xiàng),本例中 New 和 Old 表示把屬性新舊兩個(gè)值都傳遞給觀察者,這些值是NSKeyValueObservingOptions 類型的成員; context 參數(shù)是上下文內(nèi)容,它的類型是C語言形式的任何指針類型,

      Swift版表示為 UnsafeMutablePointer ,Objective-C版本表示為 void * 。

      觀察者 AppStatusObserver 的代碼如下:

      觀察者 AppStatusObserver 的代碼

      因?yàn)?NSObject 類實(shí)現(xiàn)了 NSKeyValueObserving 協(xié)議,所以只需聲明 AppStatusObserver 繼承了 NSObject 類,而無需實(shí)現(xiàn) NSKeyValueObserving 協(xié)議。

      observeValueForKeyPath:ofObject:change:context: 方法的 observeValueForKeyPath 參數(shù)是被關(guān)注的屬性。

      ofObject 是被關(guān)注的對象, change 是字典類型,包含了屬性變化的內(nèi)容,這些內(nèi)容與注冊時(shí)屬性變化設(shè)置的選項(xiàng)( options 參數(shù))有關(guān)。 context 是注冊時(shí)傳遞的上下文內(nèi)容。

      第一次運(yùn)行程序到界面時(shí),會有兩個(gè)狀態(tài)的變化,日志結(jié)果如下:

      第一次運(yùn)行程序到界面時(shí),會有兩個(gè)狀態(tài)的變化

      如果將應(yīng)用退到后臺,然后再回到前臺,日志結(jié)果如下:

      如果將應(yīng)用退到后臺,然后再回到前臺

      關(guān)于應(yīng)用程序狀態(tài)變化相關(guān)的內(nèi)容,這里不再解釋。

      本文僅限內(nèi)部技術(shù)人員學(xué)習(xí)交流,不得作于其他商業(yè)用途.希望此文對廣大技人員有所幫助。文章出自:南昌APP開發(fā)制作公司--百恒網(wǎng)絡(luò):http://www.dgscpc.com

      400-680-9298,0791-88117053
      掃一掃關(guān)注百恒網(wǎng)絡(luò)微信公眾號
      掃一掃打開百恒網(wǎng)絡(luò)小程序

      歡迎您的光顧,我們將竭誠為您服務(wù)×

      售前咨詢 售前咨詢
       
      售前咨詢 售前咨詢
       
      售前咨詢 售前咨詢
       
      售前咨詢 售前咨詢
       
      售前咨詢 售前咨詢
       
      售后服務(wù) 售后服務(wù)
       
      售后服務(wù) 售后服務(wù)
       
      備案專線 備案專線
       
      ×
      野花国产精品入口| 久久成人国产精品| 日韩中文无码有码免费视频| 在线精品一区二区三区电影| 国产精品成人在线| 日韩精品国产另类专区| 精品久久久久久久| 91精品一区国产高清在线| 亚洲精品456播放| 日本一区二区三区精品国产 | 亚洲精品无码不卡在线播放| 91麻豆精品国产片在线观看| 久久精品亚洲视频| 久久精品夜色国产亚洲av| 亚洲韩国精品无码一区二区三区| 九九热这里只有国产精品| 亚洲国产精品成人一区| chinese精品男同志浪小辉| 日韩精品中文字幕无码专区| 日韩乱码人妻无码中文字幕视频| 国产精品白丝喷水在线观看| 在线观看精品一区| 精品丝袜人妻久久久久久| www亚洲精品久久久乳| 国产精品无码一区二区在线观| 国产成人精品午夜福利在线播放| 国产成人精品久久免费动漫 | 国产精品一区二区无线| 国产精品福利久久香蕉中文| 国产精品福利午夜在线观看| 国产馆精品推荐在线观看| 国产精品社区在线观看| 国产精品91在线播放| 国产精品18久久久久久麻辣| 国产精品成年片在线观看| 国产手机精品视频| 国产成人精品免费直播| 无码日韩精品一区二区人妻| 中文字幕在线观看日韩| 亚洲高清日韩精品第一区 | 一夲道无码人妻精品一区二区|