323,IOS中觀察者模式的定義

觀察者模式(Observer Pattern):定義對象間的一種一對多依賴關(guān)系邪媳,使得每當一個對象狀態(tài)發(fā)生改變時升酣,其相關(guān)依賴對象皆得到通知并被自動更新幻工。
在iOS中典型的觀察者模式實現(xiàn)方式為NSNotificationCenter和KVO巫延。

一效五、NSNotificationCenter

image.png

在Cocoa Touch框架中NSNotificationCenter和NSNotification對象實現(xiàn)了一對多的模型。通過NSNotificationCenter可以讓對象之間進行通訊炉峰,即便這些對象之間并不認識畏妖。NSnotificationCenter是一種典型的有調(diào)度中心的觀察者模式實現(xiàn)方式。以NSNotificationCenter為中心疼阔,觀察者往Center中注冊對某個主題對象的變化感興趣戒劫,主題對象通過NSNotificationCenter進行變化廣播。這種模型就是文章開始發(fā)布訂閱報紙在OC中的一種類似實現(xiàn)婆廊。所有的觀察和監(jiān)聽行為都向同一個中心注冊迅细,所有對象的變化也都通過同一個中心向外廣播。

NSNotificationCenter就像一個樞紐一樣淘邻,處在整個觀察者模式的核心位置茵典,調(diào)度消息在觀察者和監(jiān)聽者之間傳遞。NSNotificationCenter的底層實現(xiàn)原理請看[NSNotificationCenter實現(xiàn)原理]宾舅。(http://www.reibang.com/p/07342191866b)

1.觀察者Observer统阿,一般繼承自NSObject,通過NSNotificationCenter的addObserver:selector:name:object接口來注冊對某一類型通知感興趣.在注冊時候一定要注意筹我,NSNotificationCenter不會對觀察者進行引用計數(shù)+1的操作扶平,我們在程序中釋放觀察者的時候,一定要去報從center中將其移除了蔬蕊。

- (void)update:(NSNotification * )notification{
if ([[notification name] isEqualToString:@"subjectMessage"]) {
    NSLog(@"%@",@"iOS俱哥來了");
    
}
}
 NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:@selector(update:) name:@"subjectMessage" object:nil];

2.通知中心NSNotificationCenter蜻直,調(diào)度的樞紐。
3.主題對象,被觀察的對象概而,通過postNotificationName:object:userInfo:發(fā)送某一類型通知呼巷,廣播改變。

NSNotification * subjectMessage = [NSNotification notificationWithName:@"subjectMessage" object:self];
NSNotificationCenter * notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter postNotification:subjectMessage];

4.通知對象NSNotification赎瑰,當有通知來的時候王悍,Center會調(diào)用觀察者注冊的接口來廣播通知,同時傳遞存儲著更改內(nèi)容的NSNotification對象餐曼。
5.如果我們需要對監(jiān)聽進行銷毀

-(void)dealloc{
[[NSNotificationCenter defaultCenter]removeObserver:self];
}

二压储、KVO

1、實現(xiàn)機理
當某個類的對象第一次被觀察時源譬,系統(tǒng)就會在運行期動態(tài)地創(chuàng)建該類的一個派生類集惋,在這個派生類中重寫基類中任何被觀察屬性的 setter 方法。
派生類在被重寫的 setter 方法實現(xiàn)真正的通知機制踩娘,這么做是基于設(shè)置屬性會調(diào)用 setter 方法刮刑,而通過重寫就獲得了 KVO 需要的通知機制。當然前提是要通過遵循 KVO 的屬性設(shè)置方式來變更屬性值养渴,如果僅是直接修改屬性對應(yīng)的成員變量雷绢,是無法實現(xiàn) KVO 的。
同時派生類還重寫了 class 方法以“欺騙”外部調(diào)用者它就是起初的那個類理卑。然后系統(tǒng)將這個對象的 isa 指針指向這個新誕生的派生類翘紊,因此這個對象就成為該派生類的對象了,因而在該對象上對 setter 的調(diào)用就會調(diào)用重寫的 setter藐唠,從而激活鍵值通知機制帆疟。此外,派生類還重寫了 dealloc 方法來釋放資源宇立。

2.實現(xiàn)方法
KVO是一種設(shè)計模式,名為觀察者.
addObserver:forKeyPath:options:context:
通知其他對象的方法,這個方法在NSObject中就已經(jīng)申明了,也就是說任何繼承自NSObject的對象都可以使用KVO.
我們來實現(xiàn)一個對象a值改變的時候去通知對象b.
新建兩個ModelA ModelB 類.
ModelA.h

#import <Foundation/Foundation.h>

@interface ModelA : NSObject
@property(nonatomic,copy)NSString * name;

@end

ModelA.m
import "ModelA.h"

@implementation ModelA

@end

ModelB.h

#import <Foundation/Foundation.h>

@interface ModelB : NSObject
@property (nonatomic, copy) NSString *sex;
@end

ModelB.m

#import "ModelB.h"

@implementation ModelB
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{

self.sex = @"female";

}
@end

然后執(zhí)行如下代碼:

- (void)viewDidLoad {
[super viewDidLoad];

ModelA * a = [[ModelA alloc]init];
ModelB * b =  [[ModelB alloc]init];
//a對象要通知b對象
[a addObserver:b forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
//2秒鐘之后就改變a的name屬性
[self delay:2 execute:^{
  //a對象屬相改變(發(fā)送通知消息)
    a.name = @"iOS俱哥";
    //打印b對象的sex屬性值
    NSLog(@"%@",b.sex);
    
    //移除a對象通知b對象
    
    [a removeObserver:b forKeyPath:@"name"];
    
}];

}
- (void)delay:(int64_t)delta execute:(dispatch_block_t)block
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delta * NSEC_PER_SEC),
               dispatch_get_main_queue(), block);
}

執(zhí)行結(jié)果打印了:female
如果注釋掉ModelB中的方法observeValueForKeyPath:ofObject:change:context:,運行時會導(dǎo)致崩潰:

image.png

image.png

A對象要通知B對象,B對象必須實現(xiàn)監(jiān)聽的方法,否則一旦有消息發(fā)送就會導(dǎo)致崩潰.

三鸯匹、通知中心與KVO的區(qū)別

1.發(fā)送機制的區(qū)別
通知中心自身就是中介者,兩個對象之間的通信通過中介者這個橋梁來發(fā)送信息.發(fā)送方不需要注冊任何的信息,所有的配置都由注冊方控制.
KVO是兩個對象之間直接進行通信,發(fā)送通知信息的一方(對象)的注冊鍵值發(fā)生變化的時候,會發(fā)送信息給被通知方.發(fā)送方主動添加被發(fā)送方注冊信息,被發(fā)送方還需要實現(xiàn)一個方法,兩方之間都需要進行些配置,使用稍有不當就會導(dǎo)致崩潰.

通知中心 3者間的關(guān)系
KVO 2者間的關(guān)系

2.使用的細節(jié)
KVO屬于被動發(fā)送消息,發(fā)送消息方的值改變了(一般都是被動改變的),才會發(fā)送信息給被發(fā)送方,通知中心屬于主動發(fā)送消息.

通知中心 主動
KVO 被動

3.使用難易程度
通知中心簡單暴力直白,KVO用著惡心,但惡心不代表不要用哦.

通知中心 簡單
KVO 復(fù)雜

3.使用場景
KVO監(jiān)聽僅限于屬性的變化,NSNotification是監(jiān)聽不局限于屬性的變化泄伪,還可以對多種多樣的狀態(tài)變化進行監(jiān)聽殴蓬,監(jiān)聽范圍廣,使用也更靈活蟋滴。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末染厅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子津函,更是在濱河造成了極大的恐慌肖粮,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件尔苦,死亡現(xiàn)場離奇詭異涩馆,居然都是意外死亡行施,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門魂那,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛾号,“玉大人,你說我怎么就攤上這事涯雅∠式幔” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵活逆,是天一觀的道長精刷。 經(jīng)常有香客問我,道長蔗候,這世上最難降的妖魔是什么怒允? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮锈遥,結(jié)果婚禮上纫事,老公的妹妹穿的比我還像新娘。我一直安慰自己迷殿,他們只是感情好,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布咖杂。 她就那樣靜靜地躺著庆寺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪诉字。 梳的紋絲不亂的頭發(fā)上懦尝,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機與錄音壤圃,去河邊找鬼陵霉。 笑死,一個胖子當著我的面吹牛伍绳,可吹牛的內(nèi)容都是我干的踊挠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼冲杀,長吁一口氣:“原來是場噩夢啊……” “哼效床!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起权谁,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤剩檀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后旺芽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體沪猴,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡辐啄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了运嗜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片壶辜。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖洗出,靈堂內(nèi)的尸體忽然破棺而出士复,到底是詐尸還是另有隱情,我是刑警寧澤翩活,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布阱洪,位于F島的核電站,受9級特大地震影響菠镇,放射性物質(zhì)發(fā)生泄漏冗荸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一利耍、第九天 我趴在偏房一處隱蔽的房頂上張望蚌本。 院中可真熱鬧,春花似錦隘梨、人聲如沸程癌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嵌莉。三九已至,卻和暖如春捻脖,著一層夾襖步出監(jiān)牢的瞬間锐峭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工可婶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沿癞,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓矛渴,卻偏偏與公主長得像椎扬,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子具温,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345