觀察者模式-通知詳解

觀察者模式也叫發(fā)布/訂閱模式,是軟件設(shè)計(jì)模式中的一種诗芜。在這種模式中衡瓶,一個(gè)目標(biāo)物件管理所有相依于它的觀察者物件舌劳,并且在它本身的狀態(tài)改變時(shí)主動(dòng)發(fā)出通知。這通常透過呼叫各觀察者所提供的方法來實(shí)現(xiàn)。此種模式通常被用來實(shí)現(xiàn)事件處理系統(tǒng)盆赤。
觀察者模式的類圖如下:


屏幕快照 2018-08-22 上午10.34.11.png

可以看出它有四個(gè)角色贾富,具體如下:

抽象主題(Subject):抽象主題是一個(gè)協(xié)議,它是一個(gè)觀察者的集合容器牺六,定義添加觀察者(attach)方法颤枪,移除觀察者(detach)方法和所有觀察者發(fā)送通知的方法(notifyObserve)。
抽象觀察者(Observe):抽象觀察者也是一個(gè)協(xié)議淑际,它有一個(gè)更新(update)方法畏纲。
具體觀察者(ConcreteObserve):觀察協(xié)議具體實(shí)現(xiàn)。
具體主題(ConcerteSubject):主題協(xié)議的具體實(shí)現(xiàn)春缕。

從圖中可以看出盗胀,引入Observe和Subject這兩個(gè)協(xié)議后,觀察者模式可以完美的將觀察者和被觀察的對(duì)象分離開锄贼,不僅提高了系統(tǒng)的可復(fù)用行票灰,還降低了耦合度。

在Cocoa Touch框架中宅荤,觀察者模式的具體應(yīng)用有兩個(gè) - 通知(notification)機(jī)制和KVO(Key-ValueObserving)機(jī)制屑迂。

通知機(jī)制

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

在通知機(jī)制中對(duì)某個(gè)通知感興趣的所有對(duì)象可以成為接收者首先,對(duì)這些對(duì)象需要向通知中心(NSNotificationCenter)發(fā)出addObserve:選擇器:名稱:對(duì)象消息進(jìn)行注冊(cè)惫确,在投送對(duì)象投送通知給通知中新世手报,通知中心就會(huì)把通知廣播給注冊(cè)過的接收者。所有的接收者都不知道是誰投送的改化,更不關(guān)心細(xì)節(jié)掩蛤。投送對(duì)象與接收者是一對(duì)多的關(guān)系。接收者如果對(duì)通知不再關(guān)注陈肛,會(huì)給通知中心發(fā)出removeObserver:名稱:對(duì)象:消息解除注冊(cè)揍鸟,以后不再接收通知。


屏幕快照 2018-08-22 上午11.31.38.png

注冊(cè)通知:

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor whiteColor];
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(resignNotification:) name:@"login" object:nil];

    /** 換種方式 */
    __weak typeof(self) weakSelf = self;
    [[NSNotificationCenter defaultCenter]addObserverForName:@"drain" object:nil queue:[NSOperationQueue new] usingBlock:^(NSNotification * _Nonnull note) {
        NSLog(@"你瞅啥");
        NSLog(@"接收到通知:%@",[NSThread currentThread]);
    }];
}

-(void)resignNotification:(NSNotification *)notification{
    NSLog(@"%s",__func__);
    NSLog(@"接收到通知:%@",[NSThread currentThread]);
}

發(fā)送同步通知:

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
     [[NSNotificationCenter defaultCenter]postNotificationName:@"login" object:nil userInfo:@{}];

}

發(fā)送異步通知:

/**
 * NSPostingStyle有三種:
 NSPostNow:與postNotificationName相同(就是在哪個(gè)線程里面就是獲取當(dāng)前線程的通知隊(duì)列并且默認(rèn)采用NSPostNow發(fā)送時(shí)機(jī))
 NSPostASAP:不立即發(fā)出通知燥爷,而是在runloop匹配時(shí)調(diào)用蜈亩,即:runloop處理事件源時(shí)
 NSPostWhenIdle:runloop閑置的時(shí)候post,即:runloop進(jìn)入睡眠時(shí)
 */
/*
 NSNotificationCoalescing消息合并的方式
 NSNotificationNoCoalescing = 0, //不合并
 NSNotificationCoalescingOnName = 1,//按名稱合并
 NSNotificationCoalescingOnSender = 2,//按發(fā)送者合并
 */
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //每個(gè)線程都默認(rèn)又一個(gè)通知隊(duì)列前翎,可以直接獲取稚配,也可以alloc
    NSNotificationQueue *notificationQueue = [NSNotificationQueue defaultQueue];
    NSNotification *notification = [NSNotification notificationWithName:@"drain" object:nil];
    NSNotification * notificationtwo = [NSNotification notificationWithName:@"drain" object:nil];

    NSLog(@"發(fā)送通知before:%@",[NSThread currentThread]);
    [notificationQueue enqueueNotification:notification postingStyle:NSPostNow coalesceMask:NSNotificationNoCoalescing forModes:nil];
    [notificationQueue enqueueNotification:notificationtwo postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
    [notificationQueue enqueueNotification:notification postingStyle:NSPostWhenIdle coalesceMask:NSNotificationCoalescingOnName forModes:nil];
    NSLog(@"發(fā)送通知After:%@",[NSThread currentThread]);
}

移除通知:

[[NSNotificationCenter defaultCenter]removeObserver:self name:@"login" object:nil];
//<# #>就是<## >

輸出結(jié)果:

2018-08-22 15:20:53.382286+0800 AngelClient[4074:168069] -[ViewController resignNotification:]
2018-08-22 15:20:53.382421+0800 AngelClient[4074:168069] 接收到通知:<NSThread: 0x60c0000788c0>{number = 1, name = main}
2018-08-22 15:20:53.382513+0800 AngelClient[4074:168069] 發(fā)送通知before:<NSThread: 0x60c0000788c0>{number = 1, name = main}
2018-08-22 15:20:53.382889+0800 AngelClient[4074:168112] 你瞅啥
2018-08-22 15:20:53.383015+0800 AngelClient[4074:168112] 接收到通知:<NSThread: 0x604000267dc0>{number = 3, name = (null)}
2018-08-22 15:20:53.383172+0800 AngelClient[4074:168069] 發(fā)送通知After:<NSThread: 0x60c0000788c0>{number = 1, name = main}
2018-08-22 15:20:53.383594+0800 AngelClient[4074:168112] 你瞅啥
2018-08-22 15:20:53.383741+0800 AngelClient[4074:168112] 接收到通知:<NSThread: 0x604000267dc0>{number = 3, name = (null)}

NSNotificationCenter是單例模式,創(chuàng)建獲得共享實(shí)例的方法defaultCenter港华。其中名稱是通知的名字道川,對(duì)象是投送通知時(shí)傳遞過來的對(duì)象(不一定是self對(duì)象,如果接收者不需要,可以將其設(shè)為nil )冒萄,USERINFO是投送通知時(shí)定義的字典對(duì)象臊岸,可以用于參數(shù)的傳遞,進(jìn)行的是同步發(fā)送.NSNotificationQueue是將發(fā)送的通知加到當(dāng)前線程的隊(duì)列中尊流,進(jìn)行異步發(fā)送帅戒。
下一篇:觀察者模式-KVO詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市崖技,隨后出現(xiàn)的幾起案子逻住,更是在濱河造成了極大的恐慌,老刑警劉巖迎献,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瞎访,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡吁恍,警方通過查閱死者的電腦和手機(jī)扒秸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來冀瓦,“玉大人伴奥,你說我怎么就攤上這事」净茫” “怎么了渔伯?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵顶霞,是天一觀的道長(zhǎng)肄程。 經(jīng)常有香客問我,道長(zhǎng)选浑,這世上最難降的妖魔是什么蓝厌? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮古徒,結(jié)果婚禮上拓提,老公的妹妹穿的比我還像新娘。我一直安慰自己隧膘,他們只是感情好代态,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著疹吃,像睡著了一般蹦疑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上萨驶,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天歉摧,我揣著相機(jī)與錄音,去河邊找鬼。 笑死叁温,一個(gè)胖子當(dāng)著我的面吹牛再悼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播膝但,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼冲九,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了跟束?” 一聲冷哼從身側(cè)響起娘侍,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎泳炉,沒想到半個(gè)月后憾筏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡花鹅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年氧腰,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刨肃。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡古拴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出真友,到底是詐尸還是另有隱情黄痪,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布盔然,位于F島的核電站桅打,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏愈案。R本人自食惡果不足惜挺尾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望站绪。 院中可真熱鬧遭铺,春花似錦、人聲如沸恢准。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽馁筐。三九已至涂召,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眯漩,已是汗流浹背芹扭。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工麻顶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舱卡。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓辅肾,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親轮锥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子矫钓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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