前言:23種軟體設計模式中的觀察者模式,也是在軟體開發中,挺常用的一種設計模式。而在蘋果開發中,蘋果Cocoa框架已經給我們實現了這個設 計模式,那就是通知和KVO(Key-Value Observing),本篇博文將會先講解通知和KVO的常用方法和使用示例,然後講解觀察者模式以及對觀察者模式的實現
前言:23種軟體設計模式中的觀察者模式,也是在軟體開發中,挺常用的一種設計模式。而在蘋果開發中,蘋果Cocoa框架已經給我們實現了這個設 計模式,那就是通知和KVO(Key-Value Observing),本篇博文將會先講解通知和KVO的常用方法和使用示例,然後講解觀察者模式以及對觀察者模式的實現。
文章內容大綱:
1、KVO的使用
2、通知的使用
3、觀察者模式
正文:
1、KVO的使用
addObserver:forKeyPath:options:context:
通知其他對象的方法,這個方法在NSObject中就已經申明瞭,也就是說任何繼承自NSObject的對象都可以使用KVO.
我們來實現一個對象a值改變的時候去通知對象b,也就是說這裡b就是a的觀察者,b觀察a的變化,然後做出相應的反應.
Model_A.h和Model_A.m:
Model_B.h和Model_B.m:
最後在ViewController.h中:
輸出結果:
2016-03-10 18:02:39.955 KVO[24772:539854] 程式開始執行!
2016-03-10 18:02:41.959 KVO[24772:539854] Model_B
-----------------------------------------------------------------------------------------------------------------------------------------------------------
如果註釋掉Model_B中的方法observeValueForKeyPath:ofObject:change:context:,運行時會導致崩潰:
也就是這麼一層關係:
A對象要通知B對象,B對象必須實現監聽的方法,否則一旦有消息發送就會導致崩潰.
A對象不想通知B對象了,需要從B對象身上移除掉通知.
要想程式不出現問題,我們需要實現3步.
(主動添加B的通知) A -------> B(不實現一個方法就崩潰)
(主動移除B的通知) A ---X--> B
(重覆移除B的通知) A ---X--> B(崩潰)
用起來很惡性,還好,我們可以重覆添加B的通知而不崩潰......
但是要註意:添加的觀察者的次數要和移除觀察者的次數相等,少移除一個或者多移除一個都會造成程式崩潰:
2、 通知的使用
Model.h和Model.m
簡易封裝的通知中心類:Notification.h 和 Notification.m
在ViewController.m中:
輸出結果:
2016-03-10 20:36:20.077 通知[28333:641372]
Hello,NSConcreteNotification 0x7fbafbd0b620 {name = A; userInfo = Hello,a}!
2016-03-10 20:36:20.078 通知[28333:641372]
Hello,NSConcreteNotification 0x7fbafbd0bca0 {name = B; userInfo = Hello,b}!
3、觀察者模式
關於觀察者模式,我們百度百科一下,會找到:
觀察者模式(有時又被稱為發佈(publish )-訂閱(Subscribe)模式、模型-視圖(View)模式、源-收聽者(Listener)模式或從屬者模式)是軟體設計模式的一種。在此種模式中,一個目標物件管理所有相依於它的觀察者物件,並且在它本身的狀態改變時主動發出通知。這通常透過呼叫各觀察者所提供的方法來實現。此種模式通常被用來實現事件處理系統。
在這個圖示例中,"訂閱書刊的用戶"需要向"書刊發行機構"提供基本的註冊信息,這些信息包括用戶自己的基本信息和要"訂閱的書刊號",然後確定成為" 書刊發行機構"的用戶,然後當"書刊發行機構"開始發行書刊,就會根據"訂閱書刊的用戶"的已經提供過的基本信息,進行發行書刊。然後"訂閱書刊的用戶" 就會得到相應的書刊。
在這個"發行-訂閱"的模式中,"書刊發行機構"和"訂閱書刊的用戶"之間是靠"訂閱書刊的用戶"提供的基本有效的信息建立聯繫的。
這個"發行-訂閱"的模式也是一種觀察者模式的一個生活中非常生動的例子。"書刊發行機構"相當於觀察者模式中的一個"通知中心"的角色,會根據實際需求根據用戶信息向用戶發送消息,然後用戶作為觀察者收到這些消息之後,就會自動的根據消息來執行自己的業務邏輯。
接下來,我們要實現通知中心的抽象設計
根據需求分析,首先我們需要一個唯一的"書刊發行機構",然後可以增加和刪除書刊,同時能存儲多個書刊,然後每個書刊又可以對應多個"訂閱書刊的用戶",
另外要補充一個就是,在添加和移除用戶的介面中,我們需要傳入用戶信息對象,這個用戶信息對象我們需要用協議來約束它,我們思考一下,比如訂閱書刊,我 們當然需要用戶最基本的兩個信息,用戶的ID和用戶訂閱的書刊號,用戶的ID用於"書刊發行機構"能夠準確的發消息或者發書刊正確無誤的發對了人,這個作 用就好比我們唯一的身份證號碼的作用是一樣的。然後用戶訂閱的書刊號,就能保證"書刊發行機構"能把正確的書刊發到用戶手中,不能隨便什麼書刊都發向隨便 什麼人的吧。
所以先寫出下麵所有的公開的介面,後面再具體實現它們,這就是面向介面設計:
另外,當"書刊發行機構"有了新的書刊的時候,根據需求,創建一個書刊號,然後如果有新的用戶需要訂閱新的書刊,根據需求,創建一個用戶訂閱書刊的信息對象。
一個書刊對應每個月會在某一天發佈新書,當"書刊發行機構"的現有的書刊有了新的書發佈的時候,就會發消息通知訂閱這個書刊的用戶,然後用戶會做出及時的響應回饋。
按照觀察者模式,被觀察者發送消息,觀察者收到消息就需要立馬做出響應。這個和我們之前用的Cocoa框架已經實現的KVO和通知的模式是一樣的。
為了實現這樣的模式,我們還需要給用戶信息對象用一個協議來約束它:
接著我們為上面的公開的介面具體實現,但是我們需要選擇一個數據結構來存儲書刊號和訂閱書刊的用戶信息對象,這裡我選擇使用NSMutableDictionary的Key-Value來存儲書刊號和書刊,用NSHashTable來存儲用戶信息對象。
那麼為什麼要用NSHashTable來存儲用戶信息呢?為什麼不用別的數據結構,比如數組(NSMutableArray)或者字典(NSMutableDictionary).
因為NSHashTable會對添加進的對象持有弱引用,當添加進來的元素,外部對他持有的強引用都取消的時候,這個對象就會自動從記憶體中消除,這樣就不需要手動移除這些對象。
這個相比Cocoa給我們實現的KVO和通知,就不需要我們手動去操作實現removeObserve方法了。
雖然說,在使用NSHashTable實現的觀察者模式,觀察者對象本身就至少需要一個強引用,但是在實際開發中,觀察者往往都至少會有一個強引用的。
所以,使用NSHashTable對系統算是一個小小的優化。
然後接著我們使用前面創造的觀察者模式:
CustomerA.h和CustomerA.m:
在ViewController中,同時也把ViewController作為用戶對象,以self傳入:
列印:
2016-03-11 14:50:38.980 ObserverPattern[7958:175895] hashTable:NSHashTable {
[5] <ViewController: 0x7f93d2d26ac0>
[12] <CustomerA: 0x7f93d2c17f40>
}
2016-03-11 14:50:38.981 ObserverPattern[7958:175895] V1.0 SCIENCE
2016-03-11 14:50:38.981 ObserverPattern[7958:175895]
Hello,My Name is : CustomerA
V1.0--SCIENCE
備份的源碼鏈接: http://pan.baidu.com/s/1eQTnm50 密碼: s7su
4、自己實現KVO(以後有時間補上)
轉載註明出處:http://www.cnblogs.com/goodboy-heyang/p/5265675.html ,尊重勞動成果。
本人最大的學習來源是閱讀一直走在行業里很前面的大牛寫的博客,有的博客還可能是一個團隊寫的,本人本篇深入學習的知識都是來自閱讀它們的文章,中國有傳統美德叫飲水思源,所以在這裡也分享分享與本篇知識相關的學習資料來源(附有超鏈接,點擊就能跳轉):
1、《KVO的使用》
2、《通知中心NSNotificationCenter的使用》
3、《3種方式實現KVO併進行對比》
4、《手動設定實例變數的KVO實現監聽》
5、《如何自己手動寫一個KVO》
6、《需要羅列出所有的KVO的使用方法》